1

I tried the following for loop:

for(double i = 0.0; i<=0.001; i+=0.0001)
    System.out.println(i);

And I get the following output:

0.0
1.0E-4
2.0E-4
3.0000000000000003E-4
4.0E-4
5.0E-4
6.000000000000001E-4
7.000000000000001E-4
8.000000000000001E-4
9.000000000000002E-4

My questions are:

  • How do these extra .000000000000001s come?
  • Will these extra numbers always come, or is there some problem in my code?
  • Do these errors occur only in the Java language, or any other programming languages too?
  • Is double suitable for for loops?
dryairship
  • 6,022
  • 4
  • 28
  • 54
  • 7
    Welcome to the wonderful world of IEEE 754 :p – fge Jan 27 '16 at 13:28
  • this is actually not the fault of java, but comes from the approximative representation of decimal fractions in IEEE floating points – BeyelerStudios Jan 27 '16 at 13:28
  • 2
    *"Java language is inaccurate for calculations?"* > **No**. *"Float/Double in any language is inaccurate for calculations?"* > **Yes**. If you want fixed precision, use [BigDecimal](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html). – TT. Jan 27 '16 at 13:31
  • @TT. What about my other questions? – dryairship Jan 27 '16 at 13:34
  • 1
    I would have closed it, but these are 4 questions, and not all of them are answered in [this one](http://stackoverflow.com/questions/588004/is-floating-point-math-broken). But the only open question is the last one. Regarding that: You should write such a loop as `for (int i=0; i<10; i++) { double d = i * 0.0001; ... }` to avoid an **accumulation** of errors. But it will not circumvent the inherent limited precision that is described in the other answer. – Marco13 Jan 27 '16 at 13:37
  • 1
    @fge What is the full form of IEEE? I searched the net, but found something like Institute of Electrical and Electronics Engineers. I guess that's not what you mean...? – dryairship Jan 27 '16 at 13:39
  • And another side note: People are (IMHO **far** too) quick with recommending `BigDecimal`. It has its own issues, and is cumbersome to use. In most cases, the limited precision of `double` simply does not matter, and **if** you think that it matters, you should clearly explain **why** - then it's possible to judge whether `BigDecimal` really makes sense. – Marco13 Jan 27 '16 at 13:39
  • See https://en.wikipedia.org/wiki/IEEE_floating_point – Marco13 Jan 27 '16 at 13:39

2 Answers2

6

Sadly, not all numbers can be represented exactly in floating point:

For example, the decimal number 0.1 is not representable in binary floating-point of any finite precision; the exact binary representation would have a "1100" sequence continuing endlessly:

e = −4; s = 1100110011001100110011001100110011..., where, as previously, s is the significand and e is the exponent.

When rounded to 24 bits this becomes

e = −4; s = 110011001100110011001101, which is actually 0.100000001490116119384765625 in decimal.

Vlad
  • 18,195
  • 4
  • 41
  • 71
1

Try using BigDecimal, here is my example code:

import java.math.BigDecimal;

public class Test {

    private static final BigDecimal UPPER_LIMIT = new BigDecimal(0.001);
    private static final BigDecimal STEPS = new BigDecimal(0.0001);

    public static void main(String[] args) {
        for(BigDecimal i = BigDecimal.ZERO; i.compareTo(UPPER_LIMIT) != 1; i = i.add(STEPS)){
            System.out.printf("%.4f\n", i);
        }

    }

}

And the output is:

0.0000
0.0001
0.0002
0.0003
0.0004
0.0005
0.0006
0.0007
0.0008
0.0009

p.s. I didnt spent time for memory management and other detail, should be much more heavy process than using primitives

HRgiger
  • 2,750
  • 26
  • 37