4

I wrote a program in java about floating point but the output obtained is not an accurate one; whereas the same program written in C did produce an accurate result.

Code Snippet:

public class One {

public static void main(String...args){

    double i, num=0.0;
    for(i=0;i<10;i++)
    num=num+0.1;
    System.out.println(num);

    }
}

output: 0.9999999999999999

The program in C goes like this

#include<stdio.h>
main()
{

double i,num=0.0;
for(i=0;i<10;i++)
num=num+0.1;

printf("%f",num);

}

output:1.00000

What am I doing wrong?

Jan Doggen
  • 8,799
  • 13
  • 70
  • 144
  • Why you are not tagged with c? – Linga Dec 10 '13 at 12:17
  • possible duplicate of [How to make strings from floating-point numbers with '.' (dot) as a decimal separator and not more than 3 digits after floating point?](http://stackoverflow.com/questions/8712504/how-to-make-strings-from-floating-point-numbers-with-dot-as-a-decimal-sepa) – Ingo Dec 10 '13 at 12:25
  • 3
    Have you tried using the equivalent `printf` in Java? You are comparing apples and oranges. – Ingo Dec 10 '13 at 12:27

5 Answers5

5

C is hiding the problem not removing it

The idea that the C program is more accurate is a misunderstanding of what is happening. Both have imprecise answers but then by default C has rounded to 6 significant figures. Hiding the tiny error. Were you to actually use the value in a calculation (for example num==1) you'd find that both are inaccurate.

Usually it doesn't matter for well written programs

In general intelligently written programs can cope with this tiny error without difficulty. For example your program can be rewritten to recreate a double each time

double i, num=0.0;
for(i=0;i<10;i++)
   num=0.1*i;
   System.out.println(num);

}

Meaning that the error does not grow. Additionally you should never use == with doubles as the tiny inaccuracy can be visible there.

In the very very occasional occurrences where this tiny error is a problem (currency programs being the most common); bigDecimal can be used.

This isn't a problem with floating point numbers but with the conversion from base 10 to base 2.

There are fractions in base 10 that cannot be expressed exactly; for example 1/3. Similarly there are fractions that cannot be expressed exactly within binary for example 1/10. It is from this perspective that you should look at this

The problem in this case was that when you wrote "0.1", a base 10 number the computer had to convert that to a binary number, 0.1=(binary)0.00011001100110011001100110011001....... forever but because it couldn't exactly represent that in binary with the space it had it ended up as (binary)0.0001100110011001. A binary friendly number (such as 1/2) would be completely accurate until the double ran out of precision digits (at which point even binary friendly numbers couldn't be exactly represented)

1 number of decimal places not accurate

Community
  • 1
  • 1
Richard Tingle
  • 16,906
  • 5
  • 52
  • 77
2

Try using BigDecimal. Floating point number representation is an old moot point of Java (and not only).

double i;
BigDecimal num = BigDecimal.ZERO;
for(i=0;i<10;i++)
    num = num.add(new BigDecimal("0.1"));
System.out.println(num);
Andrei Nicusan
  • 4,555
  • 1
  • 23
  • 36
  • 2
    It's a wierd situation, java was honest about it whereas c tries to hide it and as such java is seen as less accurate, *sigh* – Richard Tingle Dec 10 '13 at 12:22
1

The problem is not with Java, but about how computers represent floating point numbers in binary. Some numbers are impossible to represent exactly, so you get a little bit of rounding error as you add 0.1. I suggest you read this great article for a detailed explanation. Also, there are algorithms specifically designed to minimise error when adding a sequence of numbers.

mbatchkarov
  • 15,487
  • 9
  • 60
  • 79
0

This is an issue in floating number representation. use BigDecimal

You can understand the issue here. if you run following code,

    double i, num=0.0;
    for(i=0;i<10;i++) {
        System.out.println(num);
        num=num+0.1;
    }
    System.out.println(num);

Out put

0.0
0.1
0.2
0.30000000000000004 // wrong value, it should be 0.3
0.4
0.5
0.6
0.7
0.7999999999999999 // this one should be 0.7+0.1=0.8
0.8999999999999999 // this should be 0.8+0.1=0.9
0.9999999999999999 // final result should be 0.9+0.1=1

Let's try with BigDeciaml

 double i;
 BigDecimal num=BigDecimal.ZERO;
 for(i=0;i<10;i++) {
     System.out.println(num);
     num=num.add(new BigDecimal("0.1"));
   }
 System.out.println(num);

Out put

0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
Ruchira Gayan Ranaweera
  • 34,993
  • 17
  • 75
  • 115
0

There is a strictfp keyword, like:

strictfp class Example
{
    //your code here
}

strictfp is a keyword introduced in Java SE 2(or somewhere near that) as the floating point model was relaxed a little.

Ved
  • 389
  • 3
  • 7
  • 16
  • Could you explain what `strictfp` means/does – Richard Tingle Dec 10 '13 at 12:35
  • By my reading strictfp ensures equivalent floating point behaviour on all systems rather than using a base-10 number system rather than a base-2 – Richard Tingle Dec 10 '13 at 12:38
  • @RichardTingle Base-10 has nothing to do with floating-point. `strictfp` just ensures IEEE754 compliance via whatever means are necessary, e.g. using software instead of FP instructions. – user207421 Dec 10 '13 at 22:58
  • @EPJ that's my point, that strictfp doesn't impact this problem; representing base-10 numbers in a base-2 system (floating point would cause issues eventually but its the base-10 --> base-2 where most of the problem lies) – Richard Tingle Dec 10 '13 at 23:34