note 76702 deleted from function.round by danbrown
| From: | danbrown@php.net | Date: | Sun, 17 May 2009 16:17:41 +0000 |
| Subject: | note 76702 deleted from function.round by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-154788@lists.php.net to get a copy of this message | ||
Note Submitter: smithaapc at NOSPAM dot yahoo dot com
----
round() is broken, plain and simple. The solution must take into account all of the digits of a
given number during rounding. Truncating the number before the rounding eliminates valuable
information. Consider:
myRound(12.4444444443, 2) = 12.45 ... not quite.
Try this out instead:
function trueRound($value, $figs=1) {
if(is_numeric($value) && is_int($figs) && $figs > 0) {
// must adjust $figs down 1 for computing significant figures
$figs--;
// $prec ensures all of the original digits are included in the sprintf format
$prec = strpos($value, '.') === false ? strlen($value)-1 : strlen($value)-2;
$sci = sprintf('%.'.$prec.'e', $value);
list($sig, $mant) = explode('e', $sci);
// $base includes all of the significant digits, $test contains all the remaining digits
list($base, $test) = explode('.', $sig * pow(10, $figs));
// All 4's on the left side of $test will not be significant in the rounding
$test = preg_replace('/^4+/', '', $test);
// The first digit in $test that is not a 4 will determine the direction of the rounding
$test = preg_replace('/^(\d)\d+/', '$1', $test);
if($test > 4) {
// If the digit is > 4, then simply round up by adding 1 ...
$base += 1;
}
// ... then simply adjust the decimal point
$value = $base * pow(10, $mant-$figs);
}
return($value);
}
Note this function rounds up to a number of significant figures (all digits) rather than significant
digits (digits after the decimal point). Rounding down could be easily accomplished by passing a
switch along with the other parameters.
Mike