issue in double value comparison with php

时光总嘲笑我的痴心妄想 提交于 2021-02-16 03:10:05

问题


I try to create unit test cases to check my table values are correct or wrong.

This is my codes

echo $a = 2/9;
echo "<br>".$b=0.22222222222222;

echo "<br>".gettype($a);
echo "<br>".gettype($b);
if($a==$b){
    echo "<br>". "equal";
}else echo "<br>". "Not equal";


if((string)$a==(string)$b){
    echo "<br>". "equal";
}else echo "<br>". "Not equal";

Why my first if condition not working? I can't find the reason. Please help me.


回答1:


The test violates a cardinal rule of floating point programming: never do equality comparisons.

There are a number of problems that stem from the fact that floating point fractions have a large yet finite number of bits. These problems are commonly called "rounding errors" although for the most part they are not errors but format limitations.

For example, because of the way we write numbers when programming ... as decimal strings ... most of the numbers we can write do not have a corresponding representation in the floating point format if they have a decimal fraction. The fractional part repeats in base two.

This largely rules out comparing floating point numbers exactly, except, ironically, between integral values. You need to implement a fuzzy comparison such as abs(a - b) < epsilon.

And actually, your 2/9 is a jackpot case that doesn't have a finite representation as either a decimal string or a binary string!1

To compare 2/9 successfully for equality with a constant places more requirements for perfection on the program, the interpreter, and library than can be counted on.

For example, you would have to type more 2s than you need and the interpreter would have to round the constant's low order bits with knowledge of more precision than the format has. The machine actually has a few bits of extra knowledge when performing the operation but the interpreter may not when converting the constant. Also, the runtime rounding is subject to various options and a language like PHP may not even specify exactly how unrepresentable constants are rounded from source code to internal form.

And actually it's worse than that, because the individual 0.2 / 10n components in the decimal string also do not have exact binary equivalents. So, it's quite likely that a really perfect and faithful conversion of 0.22222222222222 does not actually equal a best-effort representation of the actual 2/9. You cannot express as a finite decimal string the exact base-2 fraction that most closely represents 2/9 in any specific (finite) number of bits.

(We must have somewhere a standard answer about not doing equality comparisons with floating point numbers.)


1. Every machine fraction is a rational number of the form x/2n. Now, the constants are decimal and every decimal constant is a rational number of the form x/(2n * 5m). The 5m numbers are odd, so there isn't a 2n factor for any of them. Only when m == 0 is there a finite representation in both the binary and decimal expansion of the fraction. For example, 1.25 is exact because it's 5/(22*50) but 0.1 is not because it's 1/(20*51). And for the rational number 2/9, there is neither a 2nor a 5m factor.




回答2:


Floats are tricky, you need to limit the number of decimal points.

$a = 2/9;
$b=0.22222222222222;

$a = number_format($a, 9);
$b = number_format($b, 9);

echo "a = " . $a . " and b = " . $b;

echo "<br>".gettype($a);
echo "<br>".gettype($b);
if($a==$b){
    echo "<br>". "equal";
}else echo "<br>". "Not equal";


if((string)$a==(string)$b){
    echo "<br>". "equal";
}else echo "<br>". "Not equal";



回答3:


If you have a look at the PHP documentation of floating point numbers (which includes doubles), you'll quickly see that it's incredible difficult to compare because of the nature of floating point numbers.

So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality.

The documentation provide an example as well:

<?php

$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if(abs($a-$b) < $epsilon) {
    echo "true";
}


来源:https://stackoverflow.com/questions/9867108/issue-in-double-value-comparison-with-php

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!