PHP's [Lack of] Floating Point Precision

Jacob Allred
#web-dev

If you do a lot of programming in PHP, it is important to know that the way PHP handles floating points (like 1.0) has a few “gotchas” that you need to be on the look out for. In most cases, these issues won’t cause any major problems, but if you have a large invoicing or payment system that does hundreds or thousands of calculations, they could cause some serious issues.

For example, take this simple subtraction:

echo 20.01 - 20.00;
// Output: 0.010000000000002

Well that doesn’t seem right. Sure, rounding the number to two decimal places “solves” the issue. But what if instead of subtracting a floating point we were to compare two floating points?

$value1 = 10.00 + 2.88 + 2.88 + 2.88 + 9.00; // 27.64
$value2 = 27.64;

if ($value1 == $value2) {
    echo 'Equal';
} else {
    echo 'Not Equal';
}

// Output: Not Equal

Even though both values should be equal, PHP doesn’t think they are.

The problem is some values are difficult to store as binary, so PHP stores approximate values. This leaves us with the question is: how do you safely deal with floating point numbers in PHP?

The easiest way is to use BC Math. For the first example above, we’d do:

bcscale(2); // Set the default precision

echo bcsub(20.01, 20.00);
// Output: 0.01

The bcscale() function sets the default precision. If I didn’t specify the precision, bcsub() would have returned 0, because 20 - 20 = 0.

For the second example above:

bcscale(2); // Set the default precision

$value1 = 10.00 + 2.88 + 2.88 + 2.88 + 9.00; // 27.64
$value2 = 27.64;

if (bccomp($value1, $value2) === 0) {
    echo 'Equal';
} else {
    echo 'Not Equal';
}

// Output: Equal

Again, bcscale() sets the default precision so we can accurately compare the two numbers.