0

Consider the following code in Java :

String input = "33.3";
float num = Float.parseFloat(input);  
System.out.printf("num: %f\n",num);      

Why is the output of the code above

num: 33.299999 ?

Shouldn't it be

num: 33.300000 ?

I would really appreciate it if someone can explain this to me.

2

4 Answers 4

7

You're a victim of floating-point error. In base 2, 33.3 is technically a repeating binary(similar to a repeating decimal), as when written as m/n with m and n being integers and gcd(m,n)=1, the prime factors of n are not a subset of the prime factors of 2. This also means that it cannot be written as the sum of a finite number of terms m*(2^n) where m and n are integers.

A similar example happens with 7/6 in base 10.

   _
1.16

becomes

1.16666667

which is then read literally, and is not equal to 7/6.

Sign up to request clarification or add additional context in comments.

10 Comments

In binary there is no decimal point, only a binary point, so it's a repeating binary (not a repeating decimal)
@Bohemian You're right, I should use the semantically correct term.
@Bohemian Even 0.1 is a repeating binary as it is not a simple sum of powers of 2.
@PeterLawrey sure. My comment was more about terminology. If in the decimal system we have a decimal point and decimal places, in the binary system we must have a binary point and binary places, etc.
@Bohemian I agree with you, but it comes as a surprise to some that 0.1 is not represented exactly but as a rounded repeating binary.
|
3

Don't use float if you can avoid it. The problem here is that %f is treating it as a double when it doesn't have that precision

String input = "33.3";
double num = Double.parseDouble(input);
System.out.printf("num: %f\n",num);

prints

33.300000

This occurs because 33.3f != 33.3 as float has less precision. To see the actual values you can use BigDecimal which covers the actual value precisely.

System.out.println("33.3f = " + new BigDecimal(33.3f));
System.out.println("33.3 = " + new BigDecimal(33.3));

prints

33.3f = 33.299999237060546875
33.3 = 33.2999999999999971578290569595992565155029296875

As you can see the true value represented is slightly too small in both cases. In the case of how %f it shows 6 decimal places even though float is not accurate to 8 decimal places in total. double is accurate to 15-16 decimal places and so you won't see an error unless the value is much larger. e.g. one trillion or more.

6 Comments

Problem is, technically even that's not exactly 33.3, which is not representable in any binary floating-point system.
@ChrisJester-Young Except perhaps one that uses 2 fixed-precision integers akin to a rational number.
@ChrisJester-Young But when you print it, it will round it to the correct value.
@hexafraction (Misread your comment, sorry.) Yes, you can create a rational type, and it'd indeed work. In fact, some programming languages have built-in rationals. <3
@hexafraction or perhaps the writers of the Double.toString(double) knew what they were doing ;)
|
1

The problem is simply that float has finite precision.

Comments

1

32-bit floating point numbers contain enough precision for about 7 decimal places of accuracy. 33.29999 is 7 decimal places. Change "input" to be 3.3 -- you should see 3.300000 Change "input" to be 333.3 -- you will see something like :333.299988 Using a 64-bit floating point number will give you more precision (15-17 decimal places).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.