Release in double value comparing with php

I am trying to create unit test cases to verify that my table values ​​are correct or incorrect.

These are 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 is my first if condition not working? I can not find the reason. Please help me.

+6
source share
3 answers

The test violates the cardinal rule of floating point programming: never conduct equality comparisons.

There are a number of problems associated with the fact that floating point fractions have a large but finite number of bits. These problems are usually called "rounding errors", although for the most part these are not errors, but format restrictions.

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

This largely eliminates the comparison of floating-point numbers exactly, except, paradoxically, between the integral values. You need to implement a fuzzy comparison, for example abs(a - b) < epsilon.

And in fact, your 2/9 is a jackpot that has no final representation of either a decimal string or a binary string! 1

For comparison, 2/9 successfully for equality with a constant puts more requirements for excellence in the program, interpreter and library than can be considered.

For example, you would need to type more than 2 than you need, and the interpreter would have to combine the bit of the low-order constant bit with knowledge of greater accuracy than the format. The machine actually has a few bits of additional knowledge when performing the operation, but the interpreter cannot do this when converting the constant. In addition, rounding at runtime depends on various parameters, and a language such as PHP may not even indicate exactly how unpredictable constants are rounded from source to internal form.

And in fact, this is worse because the individual 0.2 / 10 n components in the decimal string also do not have exact binary equivalents. Thus, it is likely that a truly perfect and accurate conversion of 0.22222222222222 really is not really equal to the best representation of the actual 2/9 . You cannot express in the form of a final decimal string the exact fraction of base-2, which most accurately represents 2/9 in any particular (final) number of bits.

(We should have somewhere a standard answer about not comparing comparisons with floating point numbers.)


<sub> 1. Each machine fraction is a rational number of the form x / 2 n . Now the constants are decimal, and each decimal constant is a rational number of the form x / (2 n * 5 m ). The number 5 m is odd, so for any of them 2 n does not exist. Only when m == 0 is the final representation in both binary and decimal fractions. For example, 1.25 is accurate because 5 / (2 2 * 5 0 ), but 0.1 not because 1 / (2 0 * 5 1 ). And for a rational number 2/9 there is no factor 2 n or 5 m .

+10
source

Floats are complex, 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"; 
+4
source

If you look at the PHP documentation for floating point numbers (which includes doubles), you will quickly see that it is incredibly difficult to compare because of the nature of the floating point numbers.

Therefore, never trust the action of a floating-point number to the last digit and do not compare floating-point numbers directly for equality.

The documentation also gives an example:

 <?php $a = 1.23456789; $b = 1.23456780; $epsilon = 0.00001; if(abs($a-$b) < $epsilon) { echo "true"; } 
+3
source

Source: https://habr.com/ru/post/911646/


All Articles