Tutorial :Why does this loop never end? [duplicate]



Question:

Possible Duplicate:
problem in comparing double values in C#

I've read it elsewhere, but really forget the answer so I ask here again. This loop seems never end regardless you code it in any language (I test it in C#, C++, Java...):

double d = 2.0;  while(d != 0.0){     d = d - 0.2;  }  


Solution:1

Floating point calculations are not perfectly precise. You will get a representation error because 0.2 doesn't have an exact representation as a binary floating point number so the value doesn't become exactly equal to zero. Try adding a debug statement to see the problem:

double d = 2.0;  while (d != 0.0)  {      Console.WriteLine(d);      d = d - 0.2;  }  
  2  1,8  1,6  1,4  1,2  1  0,8  0,6  0,4  0,2  2,77555756156289E-16   // Not exactly zero!!  -0,2  -0,4  

One way to solve it is to use the type decimal.


Solution:2

(For one thing you're not using the same variable throughout, but I'll assume that's a typo :)

0.2 isn't really 0.2. It's the closest double value to 0.2. When you've subtracted that 10 times from 2.0, you won't end up with exactly 0.0.

In C# you can change to use the decimal type instead, which will work:

// Works  decimal d = 2.0m;  while (d != 0.0m) {     d = d - 0.2m;  }  

This works because the decimal type does represent decimal values like 0.2 precisely (within limits; it's a 128-bit type). Every value involved is precisely representable, so it works. What wouldn't work would be this:

decimal d = 2.0m;  while (d != 0.0m) {     d = d - 1m/3m;  }  

Here, "a third" isn't exactly representable so we end up with the same problem as before.

In general though, it's a bad idea to perform exact equality comparisons between floating point numbers - usually you compare them within a certain tolerance.

I have articles on floating binary point and floating decimal point from a C#/.NET context, which explain things in more detail.


Solution:3

I remember buying a Sinclair ZX-81, working my way through the excellent Basic programming manual, and nearly returning to the shop when I came across my first floating point rounding error.

I'd never have have imagined that people would still be having these problems 27.99998 years later.


Solution:4

You are better off using

while(f  > 0.0)   

*edit : See pascal's comment below. But if you do need to run a loop an integral, deterministic number of times, rather use an integral data type.


Solution:5

The problem is floating point arithmetic. If there is no exact binary representation for a number, then you can only store the closest number to it (just like you couldn't store the number 1/3 in decimal - you can only store something like 0.33333333 for some length of '3's.) This means that arithmetic on floating point numbers is quite often not totally accurate. Try something like the following (Java):

public class Looping {        public static void main(String[] args) {            double d = 2.0;          while(d != 0.0 && d >= 0.0) {              System.out.println(d);              d = d - 0.2;          }        }    }  

Your output should be something like:

2.0  1.8  1.6  1.4000000000000001  1.2000000000000002  1.0000000000000002  0.8000000000000003  0.6000000000000003  0.4000000000000003  0.2000000000000003  2.7755575615628914E-16  

And now you should be able to see why the condition d == 0 never happens. (the last number there is a number that is very close to 0 but not quite.

For another example of floating point weirdness, try this:

public class Squaring{        public static void main(String[] args) {            double d = 0.1;          System.out.println(d*d);        }    }  

Because there is no binary representation of exactly 0.1, squaring it does not produce the result you would expect (0.01), but actually something like 0.010000000000000002!


Solution:6

f is uninitialised ;)

If you mean:

double f = 2.0;  

This can be a effect of non-precise arthimetic on double variables.


Solution:7

it's because of the precision of floating point. use while (d>0.0), or if you must,

while (Math.abs(d-0.0) > some_small_value){    }  


Solution:8

As others have said, this is just a fundamental problem that you get when doing floating-point arithmetic to any base. It just happens that base-2 is the most common one in computers (because it admits efficient hardware implementation).

The best fix, if possible, is to switch to using some kind of quotient representation of the number for your looping, making the floating-point value be derived from that. OK, that sounds overblown! For your specific case, I'd write it as:

int dTimes10 = 20;  double d;  while(dTimes10 != 0) {     dTimes10 -= 2;     d = dTimes10 / 10.0;  }  

Here, we're really working with fractions [20/10, 18/10, 16/10, ..., 2/10, 0/10] where the iteration is done with integers (i.e., easy to get correct) in the numerator with a fixed denominator, before converting to floating-point. If you can rewrite your real iterations to work like this, you'll have great success (and they're really not much more expensive than what you were doing before anyway, which is a great trade-off to get correctness).

If you can't do this, you need use equal-within-epsilon as your comparison. Approximately, that's replacing d != target with abs(d - target) < ε, where ε (epsilon) selection can sometimes be awkward. Basically, the right value of ε depends on a bunch of factors, but it's probably best selected as 0.001 for the example iteration given the scale of the step value (i.e., it's half a percent of the magnitude of the step, so anything within that is going to be error instead of informative).


Solution:9

It doesn't stop because 0.2 i not precisely represented in two's complement so your loop never executes the 0.0==0.0 test


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »