Reputation: 31
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
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
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
Reputation: 461
Use php floor()
and ceil()
and round()
function as per your requirement.
Upvotes: -1
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