note 106395 added to function.round
| From: | cygnus2k at gmail dot com | Date: | Fri, 04 Nov 2011 16:02:00 +0000 |
| Subject: | note 106395 added to function.round | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-184306@lists.php.net to get a copy of this message | ||
Re-definition of round for early versions of php:
<?php
function roundhelper( $value, $mode)
{
$tmp_value=0.0;
if ($value >= 0.0) {
$tmp_value = floor($value + 0.5);
if (($mode == "PHP_ROUND_HALF_DOWN" && $value == (-0.5 + $tmp_value)))
{
$tmp_value = $tmp_value - 1.0;
}
} else {
$tmp_value = ceil($value - 0.5);
if (($mode == "PHP_ROUND_HALF_DOWN" && $value == (0.5 + $tmp_value)))
{
$tmp_value = $tmp_value + 1.0;
}
}
return $tmp_value;
}
function mathround( $value, $places, $mode) {
$f1=0.0;
$f2=0.0;
$tmp_value=0.0;
$precision_places=0;
/*if (!php_math_is_finite($value)) {
return $value;
}*/
$precision_places = 14 - floor(log10(abs($value)));
$f1 = pow(10, abs($places));
/* If the decimal precision guaranteed by FP arithmetic is higher than
the requested $places BUT is small enough to make sure a non-zero $value
is returned, pre-round the result to the precision */
if ($precision_places > $places && $precision_places - $places < 15) {
$f2 = pow(10, abs($precision_places));
if ($precision_places >= 0) {
$tmp_value = $value * $f2;
} else {
$tmp_value = $value / $f2;
}
/* preround the result (tmp_$value will always be something * 1e14,
thus never larger than 1e15 here) */
$tmp_value = roundhelper($tmp_value, $mode);
/* now correctly move the decimal point */
$f2 = pow(10, abs($places - $precision_places));
/* because $places < $precision_places */
$tmp_value = $tmp_value / $f2;
} else {
/* adjust the value */
if ($places >= 0) {
$tmp_value = $value * $f1;
} else {
$tmp_value = $value / $f1;
}
/* This $value is beyond our precision, so rounding it is pointless */
if (abs($tmp_value) >= 1e15) {
return $value;
}
}
/* round the temp value */
$tmp_value = roundhelper($tmp_value, $mode);
/* see if it makes sense to use simple division to round the value */
if (abs($places) < 23) {
if ($places > 0) {
$tmp_value = $tmp_value / $f1;
} else {
$tmp_value = $tmp_value * $f1;
}
} else {
/* Simple division can't be used since that will cause wrong results.
Instead, the number is converted to a string and back again using
strtod(). strtod() will return the nearest possible FP value for
that string. */
/* 40 Bytes should be more than enough for this format string. The
float won't be larger than 1e15 anyway. But just in case, use
snprintf() and make sure the buffer is zero-terminated */
//char buf[40];
snprintf($buf, 39, "%15fe%d", $tmp_value, -$places);
$buf[39] = '\0';
//tmp_value = zend_strtod(buf, NULL);
/* couldn't convert to string and back */
/*if (!zend_finite(tmp_value) || zend_isnan(tmp_value)) {
tmp_value = value;
}*/
}
return $tmp_value;
}
$numero=number_format("1254.50",2,'.','');
echo "Valor: " . mathround($numero , 0, "PHP_ROUND_HALF_DOWN") ."\n";
//SHOW 1254
$numero=number_format("1254.51",2,'.','');
echo "Valor: " . mathround($numero , 0, "PHP_ROUND_HALF_DOWN") ."\n";
//SHOW 1255
?>
----
Server IP: 190.2.55.64
Probable Submitter: 190.247.131.151
----
Manual Page -- http://www.php.net/manual/en/function.round.php
Edit -- https://master.php.net/note/edit/106395
Del: integrated -- https://master.php.net/note/delete/106395/integrated
Del: useless -- https://master.php.net/note/delete/106395/useless
Del: bad code -- https://master.php.net/note/delete/106395/bad+code
Del: spam -- https://master.php.net/note/delete/106395/spam
Del: non-english -- https://master.php.net/note/delete/106395/non-english
Del: in docs -- https://master.php.net/note/delete/106395/in+docs
Del: other reasons-- https://master.php.net/note/delete/106395
Reject -- https://master.php.net/note/reject/106395
Search -- https://master.php.net/manage/user-notes.php