I'm working on a system where I need to round down to the nearest penny financial payments. Naively I thought I would multiply up by 100, take the floor and then divide back down. However the following example is misbehaving:
echo 1298.34*100;
correctly shows:
129834
but
echo floor(1298.34*100);
unexpectedly shows:
129833
I get the same problem using intval
for example.
I suspect the multiplication is falling foul of floating point rounding. But if I can't rely on multiplication, how can I do this? I always want to round down reliably, and I don't need to take negative amounts into consideration.
To be clear, I want any fractional penny amounts to be stripped off:
1298.345 should give 1298.34
1298.349 should give 1298.34
1298.342 should give 1298.34
Since you mention you only use this for displaying purposes, you could take the amount, turn it into a string and truncate anything past the second decimal. A regular expression could do the job:
preg_match('/\d+\.{0,1}\d{0,2}/', (string) $amount, $matches);
This expression works with any number of decimals (including zero). How it works in detail:
\d+
matches any number of digits\.{0,1}
matches 0 or 1 literal dot\d{0,2}
matches zero or two digits after the dotYou can run the following code to test it:
$amounts = [
1298,
1298.3,
1298.34,
1298.341,
1298.349279745,
];
foreach ($amounts as $amount) {
preg_match('/\d+\.{0,1}\d{0,2}/', (string) $amount, $matches);
var_dump($matches[0]);
}
Also available as a live test in this fiddle.