4

This is in reference to the comments in this question:

This code in Java produces 12.100000000000001 and this is using 64-bit doubles which can present 12.1 exactly. – Pyrolistical

Is this true? I felt that since a floating point number is represented as a sum of powers of two, you cannot represent 12.1 exactly, no matter how many bits you have. However, when I implemented both the algorithms and printed the results of calling them with (12.1, 3) with many significant digits, I get, for his and mine respectively:

12.10000000000000000000000000000000000000000000000000000000000000000000000000 12.10000000000000100000000000000000000000000000000000000000000000000000000000

I printed this using String.format("%76f"). I know that's more zeros than necessary, but I don't see any rounding in the 12.1 .

Community
  • 1
  • 1
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 1
    Could you please post the code that prints those two numbers, because I have to say that I believe the other comments that say you can't represent 12.1 exactly, and the number of digits you are printing to should show just over or just under at some point. If doubles have 53 bits of mantissa, then you would expect to see variation from exact arouns the 14th significant figure. – Tony van der Peet Dec 15 '09 at 00:04
  • It's the top two answers in that question - I didn't want to repeat myself here. – Claudiu Dec 15 '09 at 00:15
  • what if you both use `strictfp` and compare the result again? in that case the result should be VM independent. (I'm not claiming without `strictfp` the language spec allow different results. don't know don't care. floats are meant to be for imprecise values anyway) – irreputable Dec 15 '09 at 00:23
  • I think the correct answer for the way your question is currently set is here http://stackoverflow.com/questions/1904321/can-12-1-be-represented-exactly-as-a-floating-point-number/1904387#1904387 . Do you mean can you represent 12.1 exactly in a java `double`? – Pool Dec 15 '09 at 01:07
  • I looked at that question, and didn't see any code that *prints* numbers, just code that calculates numbers. – Tony van der Peet Dec 15 '09 at 09:16

9 Answers9

15

No. As others noted in followups to his comment, no sum of (a finite number of) powers of two can ever add up to exactly 12.1. Just like you can't represent 1/3 exactly in base ten, no matter how many digits you use after the decimal point.

Aric TenEyck
  • 8,002
  • 1
  • 34
  • 48
  • How come the numbers printed are so exact then? The 1st answer is definitely more precise than the 2nd. – Claudiu Dec 15 '09 at 00:10
  • heh also the 'others' following up were me =P. – Claudiu Dec 15 '09 at 00:11
  • @Claudio - from what I can make out, you are rounding a `double` approximation of 12.1 to a number that ... when converted back to decimal ... is very close to 12.1. That's not surprising. – Stephen C Dec 15 '09 at 00:22
  • 3
    @Claudio - in the case where the resulting decimal number appears to be exactly 12.1, this is definitely an artefact of the library routine you are using to convert a `double` to a decimal string. It is rounding to a "human friendly" version of the number rather than displaying the mathematically closest decimal number to the `double` you have provided. – Stephen C Dec 15 '09 at 00:25
13

In binary, 12.1 is:

1100.000110011001100110011...

Since this doesn't terminate, it can't be represented exactly in the 53 significand bits of a double, or any other finite-width binary floating-point type.

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
9

Try to express 0.1 in binary:
0.5 is too big
0.25 is too big
0.125 is too big
0.0625 fits, and leaves a remainder of 0.0375
0.03125 fits, and leaves a remainder of 0.00625
0.015625 is too big
0.0078125 is too big
0.00390625 fits, and leaves a remainder of 0.00234375
0.001953125 fits, and leaves a remainder of 0.000390625

It's going to keep repeating indefinitely, creating a base 2 value of 0.00011001100...

No, it can't be expressed exactly in a double. If Java supports BCD, or fixed point decimal, that would work exactly.

wallyk
  • 56,922
  • 16
  • 83
  • 148
3

Not in binary, no. If you'll allow me to be fanciful, you could in "floating point binary coded decimal" (which, to the best of my knowledge, has never been implemented):

12.1 = 0000 . 0001 0010 0001 * (10^2)

In binary all non-zero values are of the form 1.xyz * m, and IEEE form takes advantage of this to omit the leading 1. I'm not sure what the equivalent is for FP-BCD, so I've gone for values of the form 0.xyz * m instead.

Edmund
  • 10,533
  • 3
  • 39
  • 57
  • 3
    '"floating point binary coded decimal" (which, to the best of my knowledge, has never been implemented)' -- oops, you need to read your history. It was implemented around 50 years ago. – Windows programmer Dec 15 '09 at 00:24
  • P.S. That is, it was implemented in hardware around 50 years ago, though it was also implemented in software before and after that. – Windows programmer Dec 15 '09 at 00:25
  • 1
    That is interesting and in hindsight not surprising. What I said was still correct, though: "to the best of my knowledge" etc. ;-) – Edmund Dec 15 '09 at 02:30
  • 1
    Actually the IEEE 754 floating point standard defines decimal floating point formats in densely packed decimal (10 bits = 3 digits). I've not seen those in the wild, though. http://en.wikipedia.org/wiki/IEEE_754-2008#Basic_formats – starblue Dec 16 '09 at 08:13
  • @starblue -- Thanks for that info. It makes sense to pack things a bit more efficiently (2 bits, in fact). Whether you can honestly call it "decimal" when it's base 10^3 is another matter... ;-) – Edmund Dec 16 '09 at 08:19
  • The point is representing decimal fractions exactly, and it does that. I suppose it's for applications in finance. And "millimal" would sound strange ... :-) – starblue Dec 16 '09 at 08:27
  • This is fascinating. Thanks for bringing it up. Sooo many times I come up with an "original" idea, google it, and discover it already was done. Now I pretty much expect it :) not sure how that makes me feel tho – John Henckel Jul 19 '23 at 13:41
2

I suggest reading What Every Computer Scientist Should Know About Floating Point Arithmetic. Then you'll know for sure. :)

Rich Schuler
  • 41,814
  • 6
  • 72
  • 59
  • 1
    everything java programmers should know about floats: they are not precise:) that's good enough for me. – irreputable Dec 15 '09 at 00:38
  • @irreputable What? They are very precise. They were made by some of the brightest minds to be as precise and accurate as possible, even in the face of poor usage and bad programming. They just aren't infinitely precise. – Alice Jan 30 '14 at 16:26
2

A way to see what the double is fairly exactly is to convert it to BigDecimal.

// prints 12.0999999999999996447286321199499070644378662109375
System.out.println(new BigDecimal(12.1));
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

Yes, you can exactly represent 12.1 in floating point. You merely need a decimal floating point representation, not a binary one.

Use the BigDecimal type, and you'll represent it exactly!

Alice
  • 3,958
  • 2
  • 24
  • 28
  • floating point refers specifically to the IEEE 754 specification... also BigDecimal isn't floating point – Claudiu Jan 28 '14 at 18:57
  • No, that's one implementation of floating points; floating point refers generically to any implementation that makes use of a sliding representation. [big decimal](http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html) is both a floating point and arbitrary precision implementation. Furthermore, the IEEE 754 specification DOES INDEED specify a decimal floating point representation that can hold 12.1 exactly, as well as the more well known binary ones which cannot, under the name [Decimal32](http://en.wikipedia.org/wiki/Decimal32_floating-point_format). – Alice Jan 28 '14 at 19:11
  • Oh interesting, I never knew about the decimal format! Thanks. Is there any hardware support for using that format? – Claudiu Jan 28 '14 at 19:18
  • The only piece of hardware I've ever used with a hardware decimal floating point implementation was the POWER6 and POWER6+ architectures by IBM. – Alice Jan 28 '14 at 19:23
2

No, the decimal number 12.1 cannot be represented as a finite (terminating) binary floating-point number.

Remember that 12.1 is the rational number 121/10. Note that this fraction is in lowest terms (cannot be reduced by removing common fators of the numerator an denominator).

Suppose (in order to reach a contradiction) that 121/10 could be written also as n / (2**k) where n and k are some positive integers, and 2**k denotes the kth power of two. We would have a counter-example to unique factorization. In particular

10 * n == 2**k * 121

where the left-hand side is divisible by 5 which the right-hand side is not.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
0

One option that you can use is to not store v=0.1, but instead store v10=1. Just divide by 10 when needed ( the division will create truncation error in your result but v will still be OK )

In this case you're basically doing a fixed point hack, but keeping the number in a float. But its usually not worth doing this unless you really have to.

Michael Anderson
  • 70,661
  • 7
  • 134
  • 187