开发者

Some floating point values should sum to zero in PHP, but do not [duplicate]

This question already has answers here: Closed 11 years ago.

Possible Duplicate:

Floating 开发者_JAVA技巧point inaccuracy examples

<?php
$a = 128.3;
$b = 140.7;
$c = 12.4;
echo $a-$b+$c;   //2.30926389122E-14
?>

it will display "2.30926389122E-14"

Why it is not zero?

<?php
$a = 112.7;
$b = 125.2;
$c = 12.5;
echo $a-$b+$c;   //0
?>

What's the difference between them?


It's not a bug, it's a very-well documented phenomenon of IEEE754 floating point standards.

There are a limited number of bits to represent floating point numbers and there are, let me see if I can remember, yes, an infinite number of real numbers between any two distinct numbers.

That means you cannot represent all real numbers but have to provide approximations.

The way to fix it is to not assume that numbers can be represented exactly. You should detect if a number is close enough to zero rather than equal to zero, and you can do this by choosing a suitably small error value based on your numbers and operation.

Read What Every Computer Scientist Should Know About Floating-Point Arithmetic as a detailed treatise (warning, this may be a bit of a hard read), or The Floating Point Guide has a gentler introduction as well as a link to the BC Math package for PHP (arbitrary precision arithmetic) which may be of use to you.


The PHP doc answers this better than I could:

Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error progragation must be considered when several operations are compounded.

Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....

So never trust floating number results to the last digit, and never compare floating point numbers for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.

Edit: Your question title asked how to fix. It's simple... rounding. $val = round($val, 2);

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜