From: Eric Sosman on
On 7/13/2010 7:02 AM, Screamin Lord Byron wrote:
> On 07/13/2010 03:11 AM, Arne Vajhøj wrote:
>> On 12-07-2010 12:36, Screamin Lord Byron wrote:
>>> On 07/12/2010 05:15 PM, markspace wrote:
>>>> J.H.Kim wrote:
>>>>> Hi, everyone
>>>>>
>>>>> My java compiler and interpreter cannot display floating point
>>>>> variable.
>>>>>
>>>>> public class PrintTest {
>>>>> public static void main(String[] args) {
>>>>> double a = 3.141592;
>>>>> System.out.println(a);
>>>>> }
>>>>> }
>>>>>
>>>>> The routine above does not display 3.141592.
>>>>
>>>> <http://docs.sun.com/source/806-3568/ncg_goldberg.html>
>>>>
>>>> Floating point numbers aren't exact. You can't get exactly 3.141592 out
>>>> of any floating point system. Consider using BigDecimal if you need
>>>> "exact" numbers.
>>>
>>>
>>> Well, in this example there is no calculation, and significand fits
>>> within 52 bits of IEEE 754 double type so it should be printed out as
>>> expected: 3.141592. Please someone correct me if I'm wrong.
>>
>> Even though 7 decimals digits is less than 52 bits, then it is
>> far from guaranteed that a 7 decimals number can be represented
>> exact within 52 bit.
>
> I am aware there is a problem of representing fractions in any numeral
> system (for example, decimal 0.1 can't be exactly represented in binary,
> just as 1/3 can't be exactly represented in decimal), and here we're not
> saying nothing like double d = 2. - 0.1;
>
> Am I wrong if I say that the literal 3.141592 is represented in memory
> like this: the sign is 0, the significand is 3141592 and the exponent is
> -6.

Yes, you're wrong. It is represented in memory like this:

- The sign is zero

- The significand is 7074236280275066/9007199254740992

- The exponent is 2

- ... and the bit you're missing is that the exponent's base
is not ten, but two. From this fact flow many of the
consequences that mystify you.

> There are no mathematical operations with this number, so it's sole
> representation is in fact exact, is it not?

It is not. Do the arithmetic yourself, and you'll see that the
value derived from the representation is not exactly 3.141592, but
about 1.6e-16 greater.

> The println should print it
> like it's represented, just like it prints 0.8999999999999999 as a
> result of 2. - 0.1.

If that's what it prints, your computer is broken (and not by
just a little bit, either).

--
Eric Sosman
esosman(a)ieee-dot-org.invalid
From: Patricia Shanahan on
On 7/13/2010 8:52 AM, John B. Matthews wrote:
> In article<2ZGdncexkoRQ76HRnZ2dnUVZ_oednZ2d(a)earthlink.com>,
> Patricia Shanahan<pats(a)acm.org> wrote:
>
>> Screamin Lord Byron wrote:
>>> On 07/13/2010 03:11 AM, Arne Vajhøj wrote:
>>>> On 12-07-2010 12:36, Screamin Lord Byron wrote:
>>>>> On 07/12/2010 05:15 PM, markspace wrote:
>>>>>> J.H.Kim wrote:
>>>>>>> Hi, everyone
>>>>>>>
>>>>>>> My java compiler and interpreter cannot display floating point
>>>>>>> variable.
>>>>>>>
>>>>>>> public class PrintTest {
>>>>>>> public static void main(String[] args) {
>>>>>>> double a = 3.141592;
>>>>>>> System.out.println(a);
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>> The routine above does not display 3.141592.
>>>>>> <http://docs.sun.com/source/806-3568/ncg_goldberg.html>
>>>>>>
>>>>>> Floating point numbers aren't exact. You can't get exactly 3.141592 out
>>>>>> of any floating point system. Consider using BigDecimal if you need
>>>>>> "exact" numbers.
>>>>>
>>>>> Well, in this example there is no calculation, and significand
>>>>> fits within 52 bits of IEEE 754 double type so it should be
>>>>> printed out as expected: 3.141592. Please someone correct me if
>>>>> I'm wrong.
>>>> Even though 7 decimals digits is less than 52 bits, then it is far
>>>> from guaranteed that a 7 decimals number can be represented exact
>>>> within 52 bit.
>>>
>>> I am aware there is a problem of representing fractions in any
>>> numeral system (for example, decimal 0.1 can't be exactly
>>> represented in binary, just as 1/3 can't be exactly represented in
>>> decimal), and here we're not saying nothing like double d = 2. -
>>> 0.1;
>>>
>>> Am I wrong if I say that the literal 3.141592 is represented in
>>> memory like this: the sign is 0, the significand is 3141592 and the
>>> exponent is -6. There are no mathematical operations with this
>>> number, so it's sole representation is in fact exact, is it not?
>>> The println should print it like it's represented, just like it
>>> prints 0.8999999999999999 as a result of 2. - 0.1.
>>
>> You are wrong. 3.141592 in Java is a double literal, and double is a
>> binary floating point type. See
>> http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.2
>>
>> "The details of proper input conversion from a Unicode string
>> representation of a floating-point number to the internal IEEE 754
>> binary floating-point representation are described for the methods
>> valueOf of class Float and class Double of the package java.lang."
>>
>> The actual rule for double is described in
>> http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Double.html#valueOf(java.lang.String)
>>
>> "Otherwise, s is regarded as representing an exact decimal value in
>> the usual "computerized scientific notation" or as an exact
>> hexadecimal value; this exact numerical value is then conceptually
>> converted to an "infinitely precise" binary value that is then
>> rounded to type double by the usual round-to-nearest rule of IEEE 754
>> floating-point arithmetic, which includes preserving the sign of a
>> zero value."
>>
>> The compiler's input conversion for 3.141592 is necessarily inexact
>> for the reason you mentioned in the first paragraph.
>
> I often use this online calculator to peek at the internal representation:
>
> <http://babbage.cs.qc.edu/IEEE-754/Decimal.html>
>
> For double a = 3.141592, Long.toHexString(Double.doubleToRawLongBits(a))
> yields 400921fafc8b007a, which breaks down in binary and decimal as
> follows:
>
> sign: 0 -> +
> exponent: 10000000000 = 1024 - 1023 = 1
> significand: 1.1001001000011111101011111100100010110000000001111010
> = 1.5707960000000000
>
> 2^1 * 1.570796 = 3.141592, also expanded here:
>
> <http://en.wikipedia.org/wiki/Floating_point#Overview>
>

There is also a simple pure Java way of getting the actual decimal
expansion. The BigDecimal(double) constructor and BigDecimal's toString
are both exact:

import java.math.BigDecimal;
public class DemoExactDoubleOutput {
public static void main(String[] args) {
System.out.println(new BigDecimal(3.141592));
}
}

Output:

3.14159200000000016217427400988526642322540283203125

Patricia


From: Patricia Shanahan on
On 7/12/2010 6:11 PM, Arne Vajhøj wrote:
> On 12-07-2010 12:36, Screamin Lord Byron wrote:
>> On 07/12/2010 05:15 PM, markspace wrote:
>>> J.H.Kim wrote:
>>>> Hi, everyone
>>>>
>>>> My java compiler and interpreter cannot display floating point
>>>> variable.
>>>>
>>>> public class PrintTest {
>>>> public static void main(String[] args) {
>>>> double a = 3.141592;
>>>> System.out.println(a);
>>>> }
>>>> }
>>>>
>>>> The routine above does not display 3.141592.
>>>
>>> <http://docs.sun.com/source/806-3568/ncg_goldberg.html>
>>>
>>> Floating point numbers aren't exact. You can't get exactly 3.141592 out
>>> of any floating point system. Consider using BigDecimal if you need
>>> "exact" numbers.
>>
>>
>> Well, in this example there is no calculation, and significand fits
>> within 52 bits of IEEE 754 double type so it should be printed out as
>> expected: 3.141592. Please someone correct me if I'm wrong.
>
> Even though 7 decimals digits is less than 52 bits, then it is
> far from guaranteed that a 7 decimals number can be represented
> exact within 52 bit.
>
> It would be nice if println guaranteed that any literal with less
> digits than what is max. due to size would be printed exactly
> like the literal. But I don't think that will always be the case.

I think it will if the literal has fewer than about 14 significant
digits and is in the normalized range. Let the infinitely precise value
of the decimal literal be x and the double representation y. According
to the compiler's input conversion rules, x does round to y under the
normal rounding rules.

Another decimal fraction of the same or shorter length would be too
different from x to also round to y. They would differ by more than the
gap between doubles. They would not be possible choices for the
Double.toString result.

Of course, there will be many numbers with more decimal places than x
that also round to y, including the one that is exactly equal to y.
Double.toString should pick x, because it is the shortest decimal
expansion of all those that round to y.

Once the number of significant digits gets high enough there may be
another value of the same or shorter length that also rounds to y.

Patricia
From: Arne Vajhøj on
On 13-07-2010 07:02, Screamin Lord Byron wrote:
> Am I wrong if I say that the literal 3.141592 is represented in memory
> like this: the sign is 0, the significand is 3141592 and the exponent is
> -6. There are no mathematical operations with this number, so it's sole
> representation is in fact exact, is it not? The println should print it
> like it's represented, just like it prints 0.8999999999999999 as a
> result of 2. - 0.1.

Yes.

Double in Java are IEEE 64 bit floating point and they are binary
not decimal, so you have 1/2, 1/4 etc. not 1/10, 1/100 etc..

Arne
From: Arne Vajhøj on
On 13-07-2010 17:33, Patricia Shanahan wrote:
> On 7/13/2010 8:52 AM, John B. Matthews wrote:
>> In article<2ZGdncexkoRQ76HRnZ2dnUVZ_oednZ2d(a)earthlink.com>,
>> Patricia Shanahan<pats(a)acm.org> wrote:
>>
>>> Screamin Lord Byron wrote:
>>>> On 07/13/2010 03:11 AM, Arne Vajhøj wrote:
>>>>> On 12-07-2010 12:36, Screamin Lord Byron wrote:
>>>>>> On 07/12/2010 05:15 PM, markspace wrote:
>>>>>>> J.H.Kim wrote:
>>>>>>>> Hi, everyone
>>>>>>>>
>>>>>>>> My java compiler and interpreter cannot display floating point
>>>>>>>> variable.
>>>>>>>>
>>>>>>>> public class PrintTest {
>>>>>>>> public static void main(String[] args) {
>>>>>>>> double a = 3.141592;
>>>>>>>> System.out.println(a);
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> The routine above does not display 3.141592.
>>>>>>> <http://docs.sun.com/source/806-3568/ncg_goldberg.html>
>>>>>>>
>>>>>>> Floating point numbers aren't exact. You can't get exactly
>>>>>>> 3.141592 out
>>>>>>> of any floating point system. Consider using BigDecimal if you need
>>>>>>> "exact" numbers.
>>>>>>
>>>>>> Well, in this example there is no calculation, and significand
>>>>>> fits within 52 bits of IEEE 754 double type so it should be
>>>>>> printed out as expected: 3.141592. Please someone correct me if
>>>>>> I'm wrong.
>>>>> Even though 7 decimals digits is less than 52 bits, then it is far
>>>>> from guaranteed that a 7 decimals number can be represented exact
>>>>> within 52 bit.
>>>>
>>>> I am aware there is a problem of representing fractions in any
>>>> numeral system (for example, decimal 0.1 can't be exactly
>>>> represented in binary, just as 1/3 can't be exactly represented in
>>>> decimal), and here we're not saying nothing like double d = 2. -
>>>> 0.1;
>>>>
>>>> Am I wrong if I say that the literal 3.141592 is represented in
>>>> memory like this: the sign is 0, the significand is 3141592 and the
>>>> exponent is -6. There are no mathematical operations with this
>>>> number, so it's sole representation is in fact exact, is it not?
>>>> The println should print it like it's represented, just like it
>>>> prints 0.8999999999999999 as a result of 2. - 0.1.
>>>
>>> You are wrong. 3.141592 in Java is a double literal, and double is a
>>> binary floating point type. See
>>> http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.2
>>>
>>>
>>> "The details of proper input conversion from a Unicode string
>>> representation of a floating-point number to the internal IEEE 754
>>> binary floating-point representation are described for the methods
>>> valueOf of class Float and class Double of the package java.lang."
>>>
>>> The actual rule for double is described in
>>> http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Double.html#valueOf(java.lang.String)
>>>
>>>
>>> "Otherwise, s is regarded as representing an exact decimal value in
>>> the usual "computerized scientific notation" or as an exact
>>> hexadecimal value; this exact numerical value is then conceptually
>>> converted to an "infinitely precise" binary value that is then
>>> rounded to type double by the usual round-to-nearest rule of IEEE 754
>>> floating-point arithmetic, which includes preserving the sign of a
>>> zero value."
>>>
>>> The compiler's input conversion for 3.141592 is necessarily inexact
>>> for the reason you mentioned in the first paragraph.
>>
>> I often use this online calculator to peek at the internal
>> representation:
>>
>> <http://babbage.cs.qc.edu/IEEE-754/Decimal.html>
>>
>> For double a = 3.141592, Long.toHexString(Double.doubleToRawLongBits(a))
>> yields 400921fafc8b007a, which breaks down in binary and decimal as
>> follows:
>>
>> sign: 0 -> +
>> exponent: 10000000000 = 1024 - 1023 = 1
>> significand: 1.1001001000011111101011111100100010110000000001111010
>> = 1.5707960000000000
>>
>> 2^1 * 1.570796 = 3.141592, also expanded here:
>>
>> <http://en.wikipedia.org/wiki/Floating_point#Overview>
>>
>
> There is also a simple pure Java way of getting the actual decimal
> expansion. The BigDecimal(double) constructor and BigDecimal's toString
> are both exact:
>
> import java.math.BigDecimal;
> public class DemoExactDoubleOutput {
> public static void main(String[] args) {
> System.out.println(new BigDecimal(3.141592));
> }
> }
>
> Output:
>
> 3.14159200000000016217427400988526642322540283203125

Cute.

You are using the well-known flaw in that constructor
as a useful feature!

Arne