Floating Point Precision in PHP
Published on 2021-05-20
The Problem
Sometimes, with PHP we have problems doing mathematical calculations with floats:
Here are 3 additions:
<?php
// Addition 1:
var_dump( 2161.06+1498.46 );
// result (success): float(3659.52)
// Addition 2:
var_dump( 2161.06+1498.47 );
// result (error): float(3659.5299999999997)
// Addition 3:
var_dump( 2161.06+1498.48 );
// result (success): float(3659.54)
We can see that we have a problem with the "Addition 2".
How to Solve This Problem?
Example of 2 solutions to solve this problem:
<?php
// Problem:
var_dump( 2161.06+1498.47 );
// result (error): float(3659.5299999999997)
// Solution with round function:
var_dump( round(2161.06+1498.47, 2, PHP_ROUND_HALF_UP) );
// result (success): float(3659.53)
// Solution with BC Math function:
var_dump( bcadd('2161.06', '1498.47', 13) );
// result (success): string(18) "3659.5300000000000"
The solution is therefore to use round or bcadd. (PS: bcadd which is part of the BC Math functions).
Warning 1 with BC Math functions:
BC Math functions return return a string. So be careful if you absolutely need to have floats returned to you.
Warning 2 with BC Math functions:
With bcadd, we have a problem that it ignores the rounding rules.
Rounding Rules With BC Math
Let's do some examples with the rounding rules:
<?php
// Example 1: with round function:
var_dump( round(200.000+200.009, 2, PHP_ROUND_HALF_UP) );
// Result (success): float(400.01)
// Example 2: with BC Math function:
var_dump( bcadd('200.000', '200.009', 2) );
// Result (with the rounding problem): string(6) "400.00"
We can see that we have a rounding problem with the "Example 2". We have had "400.00" when we would have preferred to have "400.01".
If we want to use the BC Math functions for example to calculate prices to the nearest cent, the solution is to create a custom function.