-1

I have spent almost all day trying to figure out why this is happening, I had code that incremented a float if it was not a whole number until it was a whole number, i'd trigger it by incrementing the value by 0.01 and the loop keeps incrementing it by 0.01 until it is an integer however it never stops, debugging it I noticed that the number to becoming increasingly inaccurate as the loop progressed leading to it being 0.0000066 out by the end.
I thought maybe the variable might had been being accessed elsewhere somehow so I created it simply in an empty "main" program:

float value = 0;
for (int i=0; i<100; i++) {
    value += 0.01f;
}
System.out.println(value); // Displays 0.99999934
System.out.println(value == 1); // Just in case it's displaying wrong in println (displays false)

Why is this not 1 by the end? I don't think it could be anything to do with data types as i'm adding a float to a float.

Lee Fogg
  • 775
  • 6
  • 22
  • 9
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Rohit Jain Jul 25 '13 at 20:50
  • @MadProgrammer 0-99 is still 100 iterations. 100 * 0.01 = 1 – DannyMo Jul 25 '13 at 20:50
  • 1
    @MadProgrammer No, it's going 100 times like it's supposed to. Doing `<= 100` would make 101 iterations. – Dennis Meng Jul 25 '13 at 20:50
  • 1
    Long story short: Do not check a float or double for equality. It (usually) doesn't work, as you just discovered. That's just how these data types work. For the long story, check the link provided by @RohitJain – Jan Dörrenhaus Jul 25 '13 at 20:54
  • @JanDoerrenhaus The short version of the story is an unfortunate shortcut. Equality is the only part of the question's program that works. `0.01f` does not “work”, and `+` does not “work”, but `==` works perfectly. “Do not use `0.01f` and `+` if you do not understand how they behave” would be much, much better advice than “Do not use `==`”. – Pascal Cuoq Jul 28 '13 at 22:36
  • @JanDoerrenhaus For instance, changing `value += 0.01f;` to `value = i * 0.01f;` makes the condition `value == 1` true after the loop. The `==` was never wrong in this condition, only the use of `0.01f` and `+` were. Changing these uses of dangerous constructs to something more thoughtful fixes the program. – Pascal Cuoq Jul 28 '13 at 22:44

2 Answers2

5

Java's floating point numbers follow IEEE floating point standards, and that means that a value such as 0.01 cannot be represented perfectly (it's a repeating decimal in binary). There is a small error that is not visible when just displaying 0.01 (it gets rounded when converted to a String), but the errors accumulate upon every add (or any other math operation); you have displayed the visible effect.

You can use double, with twice the precision, to cut way down on floating point errors, but this too will eventually show the floating point error. You can also use BigDecimal, which supports arbitrary precision.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • I think I will use integers then divide. I will have to remember this, definitely wish this didn't happen.. – Lee Fogg Jul 25 '13 at 21:25
0

Yes this is a problem with the IEEE specification of floating points. If precision is important in your application you should instead use BigDecimal

Michael Lang
  • 3,902
  • 1
  • 23
  • 37