Understanding floating point numbers in php

I know that these questions can be asked very often, but from my reading and testing it confused me a bit, and a lot of the reading that I did only confused me, because it is quite difficult.

Some people have problems with simple comparisons, but I had no problems.

For instance...

$num1 = 27.64; $num2 = 27.64; if ($num1 == $num2) { echo 'Good!'; } else { echo 'Bad!'; } // Echo "Good!" 

... and

 $num1 = 27.60; $num2 = 27.6; if ($num1 == $num2) { echo 'Good!'; } else { echo 'Bad!'; } // Echo Good 

... and

 $num1 = 27.60; $num2 = 57.60; if ($num1 <= $num2) { echo 'Good!'; } else { echo 'Bad!'; } // Echo Good 

... and

 $num1 = 25.00; $num2 = 12.50 + 12.5; if ($num1 == $num2) { echo 'Good!'; } else { echo 'Bad!'; } // Echo Good 

Then I see pages like http://patchlog.com/php/comparing-float-values-in-php/ that seem to have simple problems, and I donโ€™t understand.

I just want to understand how he has problems with his simple code, but I'm not with him.

+4
source share
6 answers

Example 1

These values โ€‹โ€‹will be the same - you assign the same decimal literal for each variable. Compare this with this code:

 $num1 = 27.64; $num2 = 10.0 + 2.88 + 2.88 + 2.88 + 9.0; //In decimal arithmetic adds to 27.64 if ($num1 == $num2) { echo 'Good!'; } else { echo 'Bad!'; } // Echo "Bad!" 

$ num2 looks like 27.64, but it really adds to something like 27.639999999999997015720509807579219341278076171875 (this is what I get when I do this calculation in Visual C ++ on my machine). $ num1 = 27.6400000000000005684341886080801486968994140625 (on my machine), so they are different.

Example 2

End 0 does not matter.

Example 3

The numbers are not within the floating point tolerance, so of course it will be different.

Example 4

12.5 is exactly represented in floating point, so 12.5 + 12.5 is also (0.5 is 2 ^ -1).

+3
source

Here is an example:

 $a = 0; for ($i = 0; $i < 100000; $i++) { $a += 0.00001; } print("$a\n"); 

You expect you to print 1 , but actually the output is 0.99999999999808 .

(result is in x86_64 architecture)

+2
source

The larger (or smaller) the floating point number, the lower the accuracy. Exactly how accurate will depend on the processor architecture.

Try all your tests with 1E30 or 1E-30 ...

+1
source

The first two have a value provided by the compiler that resolves both numbers to the same bit pattern.

I will not touch the third, as it should be clear why it works.

In the fourth case, the values โ€‹โ€‹used have well-defined, completely accurate bit patterns. Try using the numbers a little higher on the beaten path.

+1
source

You may try

  $a = '12.30'; 

as a string to get an exact match, otherwise floatbox by default removes the termination '0'.

0
source

Floating point errors occur only when there are operations whose mathematical results cannot be accurately represented in a floating point. Errors are precisely identified; they are not random or arbitrary, therefore identical results are produced when identical operations are performed.

In the first example, you assign "27.64" to $ num1 and $ num2. Here's the operation: the parser should interpret the character string "27.64" and produce a floating-point result. The parser probably produces a floating point number that is closest to 27.64. (As a hexadecimal floating-point digit, this number is 0x1.ba3d70a3d70a4p + 4. The part before โ€œpโ€ is the hexadecimal digit with the fractional part. โ€œP4โ€ means multiplication by 2 4. As the decimal digit, this is 27.6400000000000005684341886080801486968994140625.) And It produces the same number of cases, so a comparison of $ num1 and $ num2 indicates that they are equal to each other, although none of them are equal to 27.64 (since 27.64 cannot be exactly represented in a floating point).

In your second example, the floating-point number that is closest to the value of 27.60 is the same as the floating-point number that is closest to the value of 27.6, since two digits represent the same value. So, again, you get the same results.

In your third example, the values โ€‹โ€‹of two digits are far apart, so you get different floating point numbers, and a comparison shows that they are unequal.

In your fourth example, all values โ€‹โ€‹are accurately represented in floating point, so there is no error. 25, 12.50 and 12.5 are all small multiple powers of two (includes powers with a negative exponent, such as .5 = 2 -1 within the range of the floating point type, therefore, in addition, the sum of 12.50 and 12.5 is exactly representable therefore there is no rounding error when adding them, so all the results are accurate, and the comparison shows that the sum is 25.

Problems arise when people expect the same results from two different calculations, which will have the same mathematical result. A classic example is comparing ".3" with ".1 +.2". Converting the digit โ€œ.3โ€ to a floating point gives the closest represented value, which is 0x1.333333333333333p-2 (0.29999999999999999988897769753748434595763683319091796875), slightly lower .3. Converting ".1" to a floating point gives the closest represented value, which is 0x1.999999999999ap-4 (0.1000000000000000055511151231257827021181583404541015625), slightly higher .1. Converting ".2" to a floating point gives the closest represented value, which is 0x1.999999999999ap-3 (0.200000000000000011102230246251565404236316680908203125), slightly higher .2. Adding the last two values โ€‹โ€‹gives a representable value closest to their sum, which is 0x1.333333333333434-2 (0.3000000000000000444089209850062616169452667236328125). As you can see, this amount is different from the amount obtained by converting โ€œ.3โ€ to a floating point, so comparing them shows that they are unequal.

0
source

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


All Articles