开发者

round() mode ROUND_HALF_DOWN with PHP 5.2.17

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);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜