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 f开发者_运维问答loating 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 .
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.
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.
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.
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.
I suggest reading What Every Computer Scientist Should Know About Floating Point Arithmetic. Then you'll know for sure. :)
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));
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!
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 k
th 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.
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.
精彩评论