Floating point operation precision problem
First look at an example:
<code><span><span><?php</span><span>$a</span> = <span>0.1</span>; <span>$b</span> = <span>0.9</span>; <span>$c</span> = <span>1</span>; var_dump((<span>$a</span>+<span>$b</span>)==<span>$c</span>); var_dump((<span>$c</span>-<span>$b</span>)==<span>$a</span>); <span>?></span></span></code>
$a+$b==$c returns true, correct
$c-$b== $a returns false, error
Why is this happening?
After the operation, the actual returned content when the precision is 20 digits is as follows:
<code><span><span><?php</span><span>$a</span> = <span>0.1</span>; <span>$b</span> = <span>0.9</span>; <span>$c</span> = <span>1</span>; printf(<span>"%.20f"</span>, <span>$a</span>+<span>$b</span>); <span>// 1.00000000000000000000</span> printf(<span>"%.20f"</span>, <span>$c</span>-<span>$b</span>); <span>// 0.09999999999999997780</span><span>?></span></span></code>
$c-$b is 0.09999999999999997780, so comparing with 0.1 returns false
This problem occurs because floating point calculation involves Precision, when floating point numbers are converted to binary, precision may be lost.
Floating point number conversion method
The integer part adopts the remainder method divided by 2
The decimal part is rounded by multiplying by 2
For example: Convert the number 8.5 to binary
The integer part is 8
8/2=4 8%2=0
4/2=2 4%2=0
2/2=1 2%2=0
1 is smaller than 2, so there is no need to calculate. The binary representation of the integer 8 is 1000
The decimal part is 0.5
0.5x2 = 1.0
Since the decimal part after rounding is 0, there is no need to calculate further
The binary representation of the decimal 0.5 is 0.1
8.5The binary representation is 1000.1
Calculate the binary representation of the number 0.9
0.9x2=1.8
0.8x2=1.6
0.6x2=1.2
0.2x2=0.4
0.4x2=0.8
0.8x2=1.6
.... Then the loop continues. When the interception accuracy is N, the numbers after N will be rounded off, resulting in loss of accuracy.
In the above example, the precision of 0.9 is lost when converted to binary, resulting in errors during comparison.
So never believe that a floating point number is accurate to the last digit, and never compare two floating point numbers for equality.
How to correctly compare floating point numbers
1. Use the round method to process and then compare
Example:
<code><span><span><?php</span><span>$a</span> = <span>0.1</span>; <span>$b</span> = <span>0.9</span>; <span>$c</span> = <span>1</span>; var_dump((<span>$c</span>-<span>$b</span>)==<span>$a</span>); <span>// false</span> var_dump(round((<span>$c</span>-<span>$b</span>),<span>1</span>)==round(<span>$a</span>,<span>1</span>)); <span>// true</span><span>?></span></span></code>
2. Use high-precision calculation methods
When performing calculations first, use high-precision calculation methods to ensure that accuracy is not lost.
The method of high-precision operation is as follows:
bcadd adds two high-precision numbers
bccomp compares two high-precision numbers and returns -1,0,1
bcdiv divides two high-precision numbers
bcmod finds high-precision numerical remainder
bcmul multiplies two high-precision numbers
bcpow finds the power of high-precision numbers
bcpowmod finds high-precision numerical power and modulus
bcscale configures the default number of decimal points, which is equivalent to "scale=" in Linux bc
bcsqrt finds the square root of a high-precision number
bcsub Subtract two high-precision numbers
Example:
<code><span><span><?php</span><span>$a</span> = <span>0.1</span>; <span>$b</span> = <span>0.9</span>; <span>$c</span> = <span>1</span>; var_dump((<span>$c</span>-<span>$b</span>)==<span>$a</span>); <span>// false</span> var_dump(bcsub(<span>$c</span>, <span>$b</span>, <span>1</span>)==<span>$a</span>); <span>// true</span><span>?></span></span></code>
Copyright statement: This article is an original article by the blogger and may not be reproduced without the blogger's permission.
The above introduces the PHP floating point number comparison method, including aspects of the content. I hope it will be helpful to friends who are interested in PHP tutorials.