![]() |
|
|
|
#1 |
|
Posts: n/a
|
I know the following behaviour is an old problem,
but still I don't understand why such a simple piece of code: double val = 0; for(int i=0;i<10;i++) { val+=0.1; System.out.println(val); } has the following (terrible) output: 0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999 ??? Why, as a developer, I have to use a trick like this to solve the problem: java.text.DecimalFormat df = new java.text.DecimalFormat("###.########"); double val = 0; for(int i=0;i<10;i++) { val+=0.1; val = df.parse(df.format(val)).doubleValue(); System.out.println(val); } Thank you in advance Vincenzo Caselli http://www.censnet.it |
|
|
|
#2 |
|
Posts: n/a
|
wrote:
> I know the following behaviour is an old problem, > but still I don't understand why such a simple piece of code: [] > has the following (terrible) output: [] > 0.7999999999999999 > 0.8999999999999999 > 0.9999999999999999 > > > ??? Because double and float are internally represented as *binary* fractions according to the IEEE standard 754 and can therefore not represent decimal fractions exactly. http://mindprod.com/jgloss/floatingpoint.html http://www.math.byu.edu/~schow/work/...atingPoint.htm > Why, as a developer, I have to use a trick like this to solve the > problem: > > java.text.DecimalFormat df = new > java.text.DecimalFormat("###.########"); > double val = 0; > for(int i=0;i<10;i++) { > val+=0.1; > val = df.parse(df.format(val)).doubleValue(); > System.out.println(val); > } *groan* You're 95% there and yet took the TOTALLY wrong turn at the last intersection. You want to *format* numbers, so why are you using DecimalFormat.parse()??? What do you think the format() method is for? Furthermore, if you really need exact representation of decimal fractions (usually the case only for financial applications), use java.math.BigDecimal. |
|
|
|
#3 |
|
Posts: n/a
|
Michael Borgwardt <> wrote:
> http://mindprod.com/jgloss/floatingpoint.html Another good explanation of what's happening under the hood is this one: http://en.wikipedia.org/wiki/Computer_numbering_formats Wald |
|
|
|
#4 |
|
Posts: n/a
|
wrote:
> I know the following behaviour is an old problem, > but still I don't understand why such a simple piece of code: > > > double val = 0; > for(int i=0;i<10;i++) { > val+=0.1; > System.out.println(val); > } > > has the following (terrible) output: > > 0.1 > 0.2 > 0.30000000000000004 > 0.4 > 0.5 > 0.6 > 0.7 > 0.7999999999999999 > 0.8999999999999999 > 0.9999999999999999 > > > ??? > > Why, as a developer, I have to use a trick like this to solve the > problem: > > java.text.DecimalFormat df = new > java.text.DecimalFormat("###.########"); > double val = 0; > for(int i=0;i<10;i++) { > val+=0.1; > val = df.parse(df.format(val)).doubleValue(); > System.out.println(val); > } > > > Thank you in advance > Vincenzo Caselli > > http://www.censnet.it > There are two incompatible objectives for string conversion of floating point data: 1. Produce a tidy result showing only meaningful digits. 2. Produce a result that uniquely identifies the floating point number. Language and library developers pick one for the default conversion. In C, for example, printf aims for #1, defaulting to 6 digit precision. Java uses #2 as the default, producing enough digits to ensure that the reverse conversion will recover the double. The result of adding 0.1+0.1+0.1 really is different from 0.3. I don't fully understand the reason for your "trick". I would have used the DecimalFormat when aiming for tidy output, but would not have converted back or used the result in continuing calculations. Doing so throws away precision if the mathematical answer is not a short decimal fraction. For example, try substituting 1/3.0 for 0.1 in your test. If you are only concerned with exact representation of short decimal fractions, and don't need to deal with numbers like 1/3.0, consider using BigDecimal instead of double. Any number that would be improved by your trick can be exactly represented as a BigDecimal with scale=8. Patricia |
|
|
|
#5 |
|
Posts: n/a
|
<> wrote:
> I know the following behaviour is an old problem, > but still I don't understand why such a simple piece of code: It's because you're thinking in decimal, but the computer thinks in binary. 0.1 is a repeating decimal number in binary. To understand this case, we could take an analogous algorithm in decimal; say, adding 1/3 instead of 1/10. In this example, we'll give the numbers ten significant digits of precision, so: 0.3333333333 + 0.3333333333 ------------ = 0.6666666666 + 0.3333333333 ------------ = 0.9999999999 So the same thing happens with repeating decimal numbers in base 10 as well. The cumulative error from adding 0.3333333333 instead of exactly 1/3 adds up. It's only counterintuitive because you're not expecting 0.1 to be a repeating decimal, and that's because you're not thinking in base 2 like the computer is. > Why, as a developer, I have to use a trick like this to solve the > problem: > > java.text.DecimalFormat df = new > java.text.DecimalFormat("###.########"); > double val = 0; > for(int i=0;i<10;i++) { > val+=0.1; > val = df.parse(df.format(val)).doubleValue(); > System.out.println(val); > } No, you can write: DecimalFormat df = new DecimalFormat("###.########"); double val = 0; for (int i = 0; i < 10; i++) { val += 0.1; System.out.println(df.format(val)); } As Patricia said, you're assuming that the "correct" answer is achieved by truncating the result in decimal that then parsing it back again. Only in the very limited case of nice round numbers is that true. This would be a very poor idea if you were working with any kind of measured or calculated quantity. You shouldn't be assuming enough precision that rounding error will matter anyway, so there's no need to make that round trip. -- www.designacourse.com The Easiest Way To Train Anyone... Anywhere. Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation |
|
|
|
#6 |
|
Junior Member
Join Date: Jun 2009
Posts: 1
|
Hello, First of all, sorry for my ignorance. I have the following two questions:
1. Have the results showing in the program below anything to do with this discussion? I mean, is it the same problem? 2. Does my friend need to worry about this issue, if she is writing a program for a bank? Can anyone explain what is happening below? for(int i=0;i<20;i++) System.out.println(i*1.26); ----- 0.0 1.26 2.52 3.7800000000000002 5.04 6.3 7.5600000000000005 8.82 10.08 11.34 12.6 13.86 15.120000000000001 16.38 17.64 18.9 20.16 21.42 22.68 23.94 |
|
|
|
![]() |
| Thread Tools | Search this Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Java Beginners | Still Bill | Software | 3 | 02-19-2008 09:13 AM |
| Segmentation Fault in C++ | deltaone | Software | 0 | 08-02-2006 05:05 PM |
| Latest Tech Fiasco... | Ghost | A+ Certification | 30 | 01-09-2004 11:15 AM |
| New Releases: Dilbert, Law&Order, Vacation: Updated complete downloadable R1 DVD DVB & info lists | Doug MacLean | DVD Video | 1 | 07-24-2003 03:17 PM |
| New Releases: Paramount Discount, Fox Theme Packs: Updated complete downloadable R1 DVD DB & info lists | Doug MacLean | DVD Video | 0 | 07-22-2003 04:33 AM |