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
Advertisement
Answer
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 dotd{0,2}
matches zero or two digits after the dot
You 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.