3
\$\begingroup\$

I have written a PHP function that should round prices to a desired format.

E.G. 1547.86456

That should be : 1547.85

OR

if desired : 1547.86

The code has been written and it works under several conditions. BUT I wonder if I have overlooked something. AND maybe I have used solutions that could be much easier and less CPU intensive.

Hence therefore I would like to ask if anyone could see ANY errors or optional simplifications.

<?php

function RoundPrice($num, $nearest = 5){
    $BehindComma    = 2;
    $return         = str_replace(',', '', number_format($num, $BehindComma));

    if($nearest > 0){
        $props  = explode('.', $return);
        $ext    = 0;

        if(isset($props[1]) === true){
            $props[1] = round($props[1] / $nearest) * $nearest;

            if($props[1] > 100){
                $ext        = floatval(substr_replace($props[1], '.', 1, 0));

                $props[1]   = 0;
            }
            else{
                $ext        = 0;
            }
        }

        $number = str_replace(',', '', number_format($props[0].'.'.$props[1] + $ext, $BehindComma));
    }
    else{
        $number = str_replace(',', '', number_format($num, $BehindComma));
    }

    return($number);
}



$value = 1547.86456;

echo RoundPrice($value, 10);
?>
\$\endgroup\$
2
  • 2
    \$\begingroup\$ I would like to say, don't remake the existant, Round PhP Official method, this one have been through lot of strong unit-test \$\endgroup\$
    – Zeratops
    Commented Apr 21, 2015 at 10:37
  • \$\begingroup\$ @Zerotops: Ah, but you forget that this is not normal rounding. First try to understand the question before you comment. \$\endgroup\$ Commented Apr 21, 2015 at 22:05

2 Answers 2

4
\$\begingroup\$

Consider using the Money pattern which uses integer instead of float values. Otherwise you might be losing 'pennies' because of rounding errors.

A PHP implementation of the Money pattern is found here: https://github.com/mathiasverraes/money

\$\endgroup\$
2
\$\begingroup\$

This is what I made of this price rounding function:

function roundPrice($price, $nearest = 5, $decimals = 2) {
  $factor = pow(10, $decimals) / $nearest;
  return number_format(round($price * $factor) / $factor, $decimals, '.', '');
}

What it does is basically compute a factor $factor by which to multiply the price so than when we round we automatically get the nearest when we divide by the same factor after the rounding. It sounds more complex than it is.

This does give the same results as your function for $nearest = 5, but this is certainly not true for all values of $nearest. But the quality of the results is similar.

If you use this function in real life you will have to add some error checking. For instance, $nearest should never be zero!

The pow() function and / operator are computationally somewhat expensive. So I would like to avoid them, if possible. So if you can accept slight change, the function could be made into this:

function roundPrice2($price, $nearest = 0.05, $decimals = 2) {
  return number_format(round($price / $nearest) * $nearest, $decimals, '.', '');
}

Where the $nearest value should be expressed in the current money format given the number of decimals. This is as simple as it can get.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.