Sakthibalan A
Sakthibalan A

Reputation: 31

Round price up to next 5 or 10 hundredths

I want to round up prices to ensure a 5 or 0 in the hundredths place.

e.g. I have the price £74.31 I want to round to the closest 74.35 or if above £74.36 then £74.40 and the decimals I always want to end with 5 and 0.

More examples:

£74.31 would be round up to £74.35
£74.32 would be round up to £74.35
£74.33 would be round up to £74.35
£74.34 would be round up to £74.35
£74.35 would be round up to £74.35

£74.36 would be round up to £74.40
£74.37 would be round up to £74.40
£74.38 would be round up to £74.40
£74.39 would be round up to £74.40
£74.40 would be round up to £74.40

I attempted to round up prices with the below

round(($price * $rate) * 2, 1)/2;

Upvotes: 3

Views: 1091

Answers (4)

Jhecht
Jhecht

Reputation: 4435

Hopefully this makes sense, but if it doesn't some quick background:

The round($number * 2) / 2 you posted works because there are two halves in any whole. If you wanted to round to quarters you would use round($number * 4)/4, and fifths would be round($number * 5)/5. etc, etc.

Because it appears as if you want to round to the nearest nickel, there are 20 nickels in a dollar. Problem is that it is willing to move itself up/down. The same thing happens using ceil(), but it will only move upwards, which appears to be what you want.

function round_to_nickel($item, $decimals=false){
    $num = ceil($item * 20) / 20;
    return ($decimals) ? number_format($num, (int)$decimals) : $num;
}

Upvotes: 2

mickmackusa
mickmackusa

Reputation: 48001

Be very careful if your incoming value is calculated because floating point math can yield unexpected results! Please see Is floating point math broken?

My demonstration uses a loop to increment the input number by .01. This introduces problems due to precision. See these demonstrations: https://3v4l.org/Ao1oG and https://3v4l.org/RQoGl. If your input is statically declared as a float to exactly 2 decimal places, then don't worry for this task.

As a cheap way to mitigate potential disruptions for this task, after multiplying the input by 20 subtracting .1, then call ceil(), finally divide by 20. By effect, numbers originally ending in 5 (in the hundredths place) will not be rounded up, but actually remain unchanged.

For clean, concise formatting of the new float value, I recommend printf() with a format parameter that demands two decimal places in the output.

printf('£%.02f', $num, ceil($num * 20 - .1) / 20)

Unit Tests : (Demo)

for ($num = 74.30; $num < 74.41; $num += .01) {
    var_export(sprintf('%.02f => £%.02f', $num, ceil($num * 20 - .1) / 20));
    echo "\n";
}    

Output:

'74.30 => £74.30'
'74.31 => £74.35'
'74.32 => £74.35'
'74.33 => £74.35'
'74.34 => £74.35'
'74.35 => £74.35'  #not rounded up to 74.40
'74.36 => £74.40'
'74.37 => £74.40'
'74.38 => £74.40'
'74.39 => £74.40'
'74.40 => £74.40'

Upvotes: 0

Nishit Manjarawala
Nishit Manjarawala

Reputation: 461

Use php floor() and ceil() and round() function as per your requirement.

Upvotes: -1

Niklesh Raut
Niklesh Raut

Reputation: 34924

You can also try with this logic,

<?php
    $x = 74.31;
    $number = $x*100;
    if($number % 5){
      $number = $number + 5 - ($number % 5);
    }else{
      $number = $number - ($number % 5);
    }
    $number /=100;
    echo number_format((float)$number, 2, '.', '');
?>

Live demo : https://eval.in/748595

Upvotes: 1

Related Questions