-1

Possible Duplicate:
Retain precision with Doubles in java
Moving decimal places over in a double

The class speaks for itself. If you execute this code, the double values seem to be overflowed somewhat, but then it does not happen for all values and besides, if you print the number directly the output is OK.

public class test {
    public static void main(String[] args){

        for (double f=1.36; f<1.40; f+=0.01) System.out.println(f); 
             //Prints 1.36
             //       1.37
             //       1.3800000000000001   ???????
             //       1.3900000000000001   ???????

            System.out.println(1.36); //Prints 1.36
            System.out.println(1.37); //Prints 1.37
            System.out.println(1.38); //Prints 1.38
            System.out.println(1.39); //Prints 1.39
    }
}

Can somebody shed some light? If this is a bug, whats´s the best way to fix it in the code?? Any magic workaround?

Community
  • 1
  • 1
Whimusical
  • 6,401
  • 11
  • 62
  • 105
  • 6
    http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – NPE May 16 '12 at 17:01
  • Even JEval does not handle properly operations like "1400*0.001" (that´s how I tracked the bug) because of this so I don´t think is so stupid question as for voting negative – Whimusical May 16 '12 at 17:05
  • 1
    @user1352530 it is properly handled in the sense that the output is exactly as specified (as for the downvotes, it's maybe because this question is probably asked once a day so with a little search you would probably have found something, like the link I posted above which is in the [Java FAQ](http://stackoverflow.com/tags/java/info)). – assylias May 16 '12 at 17:07
  • Oops.. sorry if so. I really looked for but not enough it seems. Is difficult to query the topic if you don´t know whether is a bug or something you are doing not well and if it´s a numbers thing, print thing, as I saw jEval also fails and dont know if somebody had the patience to go trying any number that fails like me I though it was uncommon (really never seen it in 7 years). – Whimusical May 16 '12 at 17:13
  • Wasn't me but if you search for double or floating point on here, you'll find loads of questions from people who've also discovered floating points cannot represent every number in their range. – Tony Hopkinson May 16 '12 at 17:13
  • Honestly I looked on google for large scope of related issues, even put Stack Overflow in the query, and did not found it, english is neither my language and I did not know how to describe the problem as all my questions (they always end rewritten) :p. I will try SO next time directly, it seems what you cannot find here you dont find it anywhere... – Whimusical May 16 '12 at 17:17

2 Answers2

2

If you format your printed output like this, you won't see all those decimal places:

System.out.printf("%.2f",yourVariable);
skaffman
  • 398,947
  • 96
  • 818
  • 769
Mohamed Jameel
  • 602
  • 5
  • 21
  • Thanks but my var comes from a string like 2.333333333333 and I dont know the maxDecimals so I cannot limit/rounding them and formating – Whimusical May 17 '12 at 02:05
  • no worries this will work for all decimal length. – Mohamed Jameel May 17 '12 at 09:43
  • I meant that if I´m not wrong, your solution rounds to 2 decimals, which is perfect if my value in the var is 1.300000000001 = 1.30, but not if the var holds 1.34565667777, because then I loose all precission – Whimusical May 18 '12 at 10:26
1

Try

for (int i= 136; i <= 140; i++) 
    System.out.println(i / 100.0);

prints

1.36
1.37
1.38
1.39
1.4

When you print out a double, it compensates for the representation error so you don't see it. When you perform multiple arithmetic operations on a floating point value you risk adding rounding error as well which becomes apparent (to much to correct for)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I am going to study the foundation through aix (answerer) link, but I honestly cannot understand how the most popular programming language does not handle safe and transparently such a basic operation that any calculator can do.. even less for JEval that acts like one of those. Thank u! – Whimusical May 16 '12 at 17:22
  • It uses http://en.wikipedia.org/wiki/IEEE_754-2008 floating arithmetic which every major programing language and CPU supports. Calculators usually hide more digits and do other things to reduce the apparent rounding errors. Java just uses the float and double types your CPU supports. Changing the functionality significantly would add overhead and make it inconsistent with other languages. – Peter Lawrey May 16 '12 at 17:35
  • Wow, I cannot believe it. Today I learned that there's no optimal way for computers in 2012 to resolve a basic 14*0.1 (1.4000000000000001) and store it in a var :) – Whimusical May 16 '12 at 17:57
  • @user1352530 -- That's the wrong way to think about it. Instead, think about that fact that in decimal numbers, you can't represent 1/3 with a finite number of digits -- i.e., the answer is 0.33333... (repeating forever). In binary arithmetic, 1/10 is a repeating decimal -- you'd need an infinite number of bits to store the exact value -- and that's just a fact of life. We deal with this in computing by formatting output for human consumption. – Ernest Friedman-Hill May 16 '12 at 18:05
  • But what does my 5 euro (also binary) calculator that Java cannot do as an alternative at least? Printing 14*0.1 should be trivial.. I dont want to format because if I round, i need to constraint the maximum decimals allowed. Then if i put a low threeshold i loose most of the digits for bigger numbers but if i put it high, somehting like 0.1 is enough to screw up things, – Whimusical May 16 '12 at 18:15
  • @user1352530 If you want to control the decimal places exactly you can use BigDecimal, but this is can be more trouble than its worth. You always need to be aware of the limitations of the types you use or you will run into issues. – Peter Lawrey May 16 '12 at 19:27