4

I got a problem with PHP. This exact substraction below is wrongly computed.

<?php

$test = 145.48 - 80.26;

if($test != 65.22)
    echo 'not good !';
else
    echo 'good';

?>

This echoes "not good" !!!

Why ?

Maloupi
  • 43
  • 6

2 Answers2

4

Computers aren't very good at storing floating point (decimal) numbers since representing a base 10 decimal number in binary is hard. For instance, if you try to store the number 0.2 in binary, the computer will store a series following the pattern 0.00110011… . Depending on the size of the floating point number (i.e. how many bits have been allocated for it in memory), the precision will vary, but more important, it will never accurately store exactly 0.2.

There are several ways to fix this, one is using the BC Math library and do something like:

bcsub("145.48", "80.26");

But sometimes the better solution is to just acknowledge that the numbers won't be accurate and account for the error, i.e.

if (abs($x - $y) < $e)

where e is some very small number, e.g. 10^(-5). This is common practice when working with physics calculations and similar, but of course you should never attempt this when working with discrete numbers, e.g. currencies.

kba
  • 19,333
  • 5
  • 62
  • 89
  • *just acknowledge that the numbers won't be accurate* I cant believe. Computers fly spaceships nowadays. – Daniel W. Jan 20 '14 at 11:06
  • @DanFromGermany Well, BC math is accurate. Complete accuracy can be achieved, but it will cost you in both time and space efficiency. – kba Jan 20 '14 at 11:08
  • This is what helped me to understand this problem: Calculate `1/3` and store the solution with a finite number of digits (e.g. write it on a piece of paper). Multiply the number you see by `3` and you will get something like `0.999999999`. The reason you don't have `1` as result is the same reason that caused your PHP problem. – fero Jan 20 '14 at 15:19
1

To do exact floating number arithmetic you can use bc_math:

$test = bcsub("145.48", "80.26");
assert ($test == "65.22");
wroniasty
  • 7,884
  • 2
  • 32
  • 24