PHP floating point errors with basic math

Possible duplicate:
Why decimal numbers cannot be represented exactly in binary format?
with floating values

$var1 = 1; for ( $i=0; $i<30; $i++ ) { $var1 += 0.1; $var2 = floor($var1); $var3 = $var1-$var2; if ( $var3 == 0.5 ) { $var1 = $var2+1; } } 

The goal of this cycle is to read 1.0, 1.1, 1.2, 1.3, 1.4, and then move on to 2.0, 2.1, 2.2, etc.

The problem I am getting is that the if never true. Also, every tenth calculation allows some kind of crazy scientific answer.

How to fix it? please, help!

Edit: I wrote the question in a slightly frustrated rush, and it was a few, I see it now.

The first part of the question was actually β€œhow can I do this work bypassing this piece with a floating point” and β€œwhy does this querk even happen!”

Thanks for all the great answers, and I vote for the answer correctly, which easily answered the basic question "how to make this work."

Uses 0.49 instead of 0.5 and> instead of ==. Raw and not the best code in the world, but it solves the original question. Thanks to everyone for the other answers that I am going to read and monitor the improvement of my coding.

Thanks again.

+6
source share
7 answers

This gives the desired results:

 $var1 = 1; for ( $i=0; $i<30; $i++ ) { $var1 += 0.1; $var2 = (int)($var1); $var3 = $var1-$var2; if ( $var3 >= 0.45 ) { $var1 = $var2+1; } echo $var1.' '.$var2.' '.$var3.'<br/>'; } 
+5
source

Computers cannot accurately represent floats because they are stored in binary format (base 2). All floats will have a slight +/- adjustment.

See here: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

+5
source

The floating point binary will select an approximate value to represent the base-10 floating point that it cannot represent. Thus, it is inaccurate to compare float with float (because you cannot determine its behavior).

You need to invent your own base point, base-10. It's not hard to come up with if you know which one you want. In your case, you only need a single point digit. The formula for our base value of 10 will be: value / 10 for the power of our exact number, which is 1, so your formula = value / 10 .

Performing an arithmetic operation is as simple as performing ordinary arithmetic. Just convert the normal view (refers to the view that computer use) to our invented view. In your case, $var1 += 0.1 will go to $var1 += 1 .

The conclusion will be as simple as converting your view into a normal view. In your case, echo $var1 . '<br>'; echo $var1 . '<br>'; will appeal to echo $var1 / 10 . '<br>'; echo $var1 / 10 . '<br>';

 $var1 = 10; for ( $i=0; $i<30; $i++ ) { echo $var1 / 10 . '<br>'; $var1 += 1; if ($var1 % 10 == 5) { $var1 = $var1+5; } } 
+3
source

A lot of good information on why this happens, and a number of solutions. One of the main goals of PHP design is its plaintext design and implicit casting. In this spirit, I believe that one of the easiest solutions to this problem is to use string comparison. In your case, this is a great solution:

 <?php $var1 = 1; for ( $i=0; $i<30; $i++ ) { $var1 += 0.1; $var2 = floor($var1); $var3 = $var1 - $var2; echo "$var1 | $var2 | $var3 \n"; if (number_format($var3, 1) == '0.5') { echo "It true\n"; $var1 = $var2 + 1; } } 
+2
source

The correct solution is to use the bcmath package:

 $var1 = '1.0'; bcscale(1); for ( $i = 0; $i < 30; $i++) { $var2 = $var1; for( $j = 0; $j < 5; $j++) { echo $var2 . "\n"; $var2 = bcadd( $var2, '0.1'); } $var1 = bcadd( $var1, '1'); } 

This prints the correct result .

+1
source

An if statement may never be executed simply because of floating point arithmetic in general - testing strict equality with floating point values ​​always carries this risk. Why not change the condition to check for a variable that lies within a small interval centered at 0.5 to make sure you catch it?

0
source

Keep it simple, stupid and use integer arithmetic.

For example, you start with version 1.1

Why not:

 for ( $i=1; $i<4; $i++ ) { for ( $j=0; $j<5; $j++ ) { $v = $i + ($j/10); # ... } } 
0
source

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


All Articles