Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP. result of the subtraction of two floating point numbers

For example...

$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
// result is:-1198.9699999988 not the -1198,97

But in this exampe:

$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
//Result is: 0.03

Why the difference in to examples? Lacks precision?

like image 792
Andrey K. Avatar asked Nov 18 '14 21:11

Andrey K.


2 Answers

None of the numbers in your code can be expressed exactly in binary floating point. They have all been rounded somehow. The question is why one of the results has been (seemingly) rounded to two decimal digits and not the other. The answer lies in the difference between the precision and accuracy of floating point numbers and the precision PHP uses to print them.

Floating point numbers are represented by a significand (or mantissa) in the range [1, 2), which is scaled by multiplying it by a power of two. (This is what the "floating" in floating point means). The precision of the number is determined by the number of digits in the significand. The accuracy is determined by how many of those digits are actually correct. See: How are floating point numbers stored in memory? for more details.

When you echo floating point numbers in PHP, they are first converted to string using the precision configuration setting, which defaults to 14. (In Zend/zend_operators.c)

To see what is really going on, you have to print the numbers using a larger precision:

$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;

printf ("\$aa: %.20G\n", $aa);
printf ("\$bb: %.20G\n", $bb);
printf ("\$ab: %.20G\n\n", $ab);

$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;

printf ("\$cc: %.20G\n", $cc);
printf ("\$dd: %.20G\n", $dd);
printf ("\$cd: %.20G\n", $cd);

Output:

$aa: 10694994.890000000596
$bb: 10696193.859999999404
$ab: -1198.9699999988079071

$cc: 0.89000000000000001332
$dd: 0.85999999999999998668
$cd: 0.030000000000000026645

The initial numbers have a precision of about 16 to 17 digits. When you subtract $aa-$bb, the first 4 digits cancel each other out. The result, (while still having a precision of about 16 to 17 digits), is now only accurate to about 12 digits. This lower accuracy shows up when the results is printed using a 14-digit precision.

The other subtraction ($cc-$dd) loses only a single digit of accuracy, which isn't noticable when printed with a 14-digit precision.

like image 122
Nisse Engström Avatar answered Nov 15 '22 09:11

Nisse Engström


This should work for you:

(You have to round your result!)

$aa = 10694994.89;
$bb = 10696193.86;
echo $ab = round($aa - $bb, 2);
like image 42
Rizier123 Avatar answered Nov 15 '22 09:11

Rizier123