I need to simulate ROUND_HALF_开发者_开发百科DOWN mode in PHP 5.2.17 - I cannot upgrade the server's PHP version. Any ideas how to achieve this?
The basic idea is that 1.895 becomes 1.89, not 1.90 like it usually does with round().
EDIT: This function seems to do the trick:
function nav_round($v, $prec = 2) {
// Seems to fix a bug with the ceil function
$v = explode('.',$v);
$v = implode('.',$v);
// The actual calculation
$v = $v * pow(10,$prec) - 0.5;
$a = ceil($v) * pow(10,-$prec);
return number_format( $a, 2, '.', '' );
}
You can cheat by simply converting to a string and back:
$num = 1.895;
$num = (string) $num;
if (substr($num, -1) == 5) $num = substr($num, 0, -1) . '4';
$num = round(floatval($num), 2);
EDIT:
Here you have it in function form:
echo round_half_down(25.2568425, 6); // 25.256842
function round_half_down($num, $precision = 0)
{
$num = (string) $num;
$num = explode('.', $num);
$num[1] = substr($num[1], 0, $precision + 1);
$num = implode('.', $num);
if (substr($num, -1) == 5)
$num = substr($num, 0, -1) . '4';
return round(floatval($num), $precision);
}
It seems the easiest method for this prior to PHP 5.3 is to subtract 1 from the number following the last number in the required precision. So if you have precision 2 and want 1.995 to become 1.99 just subtract .001 from the number and round. This will always return a correct round except that the half value will round down rather than up.
Example1:
$num = 1.835;
$num = $num - .001; // new number is 1.834
$num = round($num,2);
echo $num;
The value after rounding is now 1.83
For another precision you just adjust where you subtract the 1 from.
Example2:
$num = 3.4895;
$num = $num - .0001; // new number is 3.4894
$num = round($num, 3);
echo $num;
The value after rounding is now 3.489
If you want a function to handle the work the following function does that.
function round_half_down($num,$precision)
{
$offset = '0.';
for($i=0; $i < $precision; $i++)
{
$offset = $offset.'0';
}
$offset = floatval($offset.'1');
$num = $num - $offset;
$num = round($num, $precision);
return $num;
}
You can take off 0.5^p where p is the precision and then use ceiling:
<?php
function round_half_down($v, $prec) {
$v = $v * pow(10,$prec) - 0.5;
return ceil($v) * pow(10,-$prec);
}
print round_half_down(9.5,0) . "\n";
print round_half_down(9.05,0) . "\n";
print round_half_down(9.051,0) . "\n";
print round_half_down(9.05,1) . "\n";
print round_half_down(9.051,1) . "\n";
print round_half_down(9.055,2) . "\n";
print round_half_down(1.896,2) . "\n";
?>
yields:
$ php test.php
9
9
9
9
9.1
9.05
1.9
You'll note that for any number x <= p <= x.5, we get ceiling(p - 0.5) = x, and for all x+1 => p > x.5, we get ceiling(p - 0.5) = x+1. This should be exactly what you want.
You can use the preg_replace for this:
$string = '1.895';
$pattern = '/(\d+).(\d+)/e';
$replacement = "'\\1'.'.'.((substr($string, -1) > 5) ? (substr('\\2',0,2) + 1) : substr('\\2',0,2))";
echo preg_replace($pattern, $replacement, $string);
精彩评论