I am trying to make an algorithm that will round according to these conditions:
- 1 or 2 cents - rounded down to "0"
- 3 or 4 cents - rounds up to 5 cents
- 5 cents - 5 cents left
- 6 or 7 cents - rounds down to 5 cents
- 8 or 9 cents - rounds up to "0"
So, it should look like this:
PRICE| AFTER
9.90 | 9.90
9.91 | 9.90
9.92 | 9.90
9.93 | 9.95
9.94 | 9.95
9.95 | 9.95
9.96 | 9.95
9.97 | 9.95
9.98 | 10.0
9.99 | 10.0
10.0 | 10.0
My code is here, but looks strange. For numbers like 10.99 result becomes 10.10:
function roundDown(float $price): float
{
[$number, $decimals] = explode('.', sprintf('%.2f', $price));
[, $second] = str_split($decimals);
$table = [
0 => 0,
1 => -1,
2 => -2,
3 => 2,
4 => 1,
5 => 0,
6 => -1,
7 => -2,
8 => 2,
9 => 1,
];
return $number . '.' . str_pad((float)$decimals (float)$table[$second], 2, '0', STR_PAD_LEFT);
}
Thanks in advance.
CodePudding user response:
What about this?
function roundDown(float $price): float
{
$denominator = 20;
return round(round($price * $denominator) / $denominator, 2, PHP_ROUND_HALF_UP);
}
CodePudding user response:
You have forgotten to carry the hundreds when you reach 100: 1.99 0.01
needs to become 2.00
Sticking to your current approach, you could check if the new "decimals" reach 100 or higher after your adj, and if so increment the "number":
function roundDown(float $price): float
{
[$number, $decimals] = explode('.', sprintf('%.2f', $price));
[, $second] = str_split($decimals);
$table = [
0 => 0,
1 => -1,
2 => -2,
3 => 2,
4 => 1,
5 => 0,
6 => -1,
7 => -2,
8 => 2,
9 => 1,
];
$newDecimals = (float)$decimals (float)$table[$second];
if ( $newDecimals > 99 ) {
$number = 1;
$newDecimals -= 100;
}
return $number . '.' . str_pad($newDecimals, 2, '0', STR_PAD_LEFT);
}
(There are various other ways to improve the code, or implement the requirement a different way, but I wanted to point out the specific bug in your current attempt, and the simplest change that fixes it.)
CodePudding user response:
I would avoid the string manipulation at the end and set the values in $table to be the actuals values to be added or subtracted and then do the arithmetic at the end.
function roundDown(float $price): float
{
[$number, $decimals] = explode('.', sprintf('%.2f', $price));
[, $second] = str_split($decimals);
$table = [
0 => 0,
1 => -0.01,
2 => -0.02,
3 => 0.02,
4 => 0.01,
5 => 0,
6 => -0.01,
7 => -0.02,
8 => 0.02,
9 => 0.01,
];
return $price $table[$second];
}