问题
Of course,
System.out.println( 0.1 );
outputs 0.1
. But is it always true for an arbitrary decimal?
(EXCLUDE cases which result from the precision of double number itself. Such as, System.out.println( 0.10000000000000000001);
outputs 0.1
)
When I hit System.out.println( DECIMAL );
I think, DECIMAL is converted into binary(double) and that binary is converted into decimal (to output decimal as String)
Think about the following conversion.
decimal[D1] -> (CONVERSION1) -> binary[B] -> (CONVERSION2) -> decimal[D2]
CONVERSION1:
(within the range of significant digits of double) The nearest binary of [D1] is selected as [B]
e.g. [D1] 0.1 -> [B] 0x0.1999999999999a
CONVERSION2:
[D2] is the decimal number which can uniquely distinguish [B] and has smallest digits.
e.g. [B] 0x0.1999999999999a -> [D2] 0.1
QUOTE Java7 API Double.toString(double d)
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
My Question :
Is "[D1]=[D2]" always true?
Why I ask this Question :
Thinking about the following case,
save user's decimal input as double -> display that decimal
I'm wondering whether [ user's input = display ] is guaranteed or not.
(As mentioned above, exclude the cases which result from the precision of double number itself. Since that long input is rare case.)
I know when I need accurate arithmetic, I should use BigDecimal. But in this case, I don't need accurate arithmetic. Just want to display the same decimal as user's input.
回答1:
It depends in part on your definition of equality. If you require exact string match, the answer is no. For example:
System.out.println(0.1e-1);
prints
0.01
Now assume that "equal" means decimal value equality, so that 0.1e-1
and 0.01
are equal.
If you limit your doubles to normal numbers (not subnormal, overflow, or underflow) with less than 16 significant decimal digits, you are safe. An infinity of decimal fractions round to each binary fraction that can be exactly represented in double. To recover the original, it has to be the shortest member of that set. That means the difference between it and the two nearest decimal numbers of the same or shorter length has to be big enough to ensure that they round to different doubles. To get another decimal number of the same or shorter length requires a change of at least one decimal ulp of the original number.
If two decimal numbers differ by more than one part in 2^54, and are in the normal number range, they are too far apart to map to the same double.
This reasoning does not apply to subnormal numbers because they have less precision than normal numbers:
System.out.println(0.123451234512345e-310);
prints
1.2345123451236E-311
even though the input has only 15 significant digits.
回答2:
The first conversion, from decimal to binary, may yield another mathematical value, because not every decimal can be represented exactly as a binary number. This is true independent of the accuracy of the binary, take 0.1 as an example.
The second conversion, from binary to decimal, is always possible in a loss-less fashion, i.e. yielding the same mathematical value. This will in general need a ridiculously long decimal representation so in practice you will round the value to a much shorter representation, which is then no longer the same mathematical value.
The answer to your question "Is [D1]=[D2] always true?" is therefore in general no. It all depends on the accuracy of the binary and the decimal representations.
来源:https://stackoverflow.com/questions/22170625/does-system-out-println-decimal-always-output-the-same-decimal-in-the-code