Floats and Doubles

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Floats and Doubles

Karsten Kusche
I’ve just come across the following scenario:

0.123456789123456d roundTo: 0.0000000000001

i’d expected the result to be around 0.1234567891234.
what actually happens is that 0.0000000000001 is a represented as a float, so the result is again a float, which is 0.123457

Why is it that Float is still the default class for floating-point kind of numbers and not Double. And why is the class not automatically changed to something with higher precision like it is for Integers?
Currently it seems that if you really need to use Double precision, you need to make sure that every literal number with a „." also has a „d“ at the end. And then you need to have tons of tests that make sure the results are as expected, which is even less fun, considering the lack of comparability in floating-point arithmetics in general. 

And then you need to remember that for the next times you or someone else needs to work on the code again.

Kind Regards
Karsten


-- 
Karsten Kusche - Dipl. Inf. (FH) - [hidden email]
Georg Heeg eK - Köthen
Handelsregister: Amtsgericht Dortmund A 12812 


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Andres Valloud-4
That's going to be hard to manage.  To begin with, 0.0000000000001 is
not representable as a floating point value.

On 8/11/14 8:45 , Karsten Kusche wrote:

> I’ve just come across the following scenario:
>
> 0.123456789123456d roundTo: 0.0000000000001
>
> i’d expected the result to be around 0.1234567891234.
> what actually happens is that 0.0000000000001 is a represented as a
> float, so the result is again a float, which is 0.123457
>
> Why is it that Float is still the default class for floating-point kind
> of numbers and not Double. And why is the class not automatically
> changed to something with higher precision like it is for Integers?
> Currently it seems that if you really need to use Double precision, you
> need to make sure that every literal number with a „." also has a „d“ at
> the end. And then you need to have tons of tests that make sure the
> results are as expected, which is even less fun, considering the lack of
> comparability in floating-point arithmetics in general.
>
> And then you need to remember that for the next times you or someone
> else needs to work on the code again.
>
> Kind Regards
> Karsten
>
>
> --
> Karsten Kusche - Dipl. Inf. (FH) - [hidden email]
> Georg Heeg eK - Köthen
> Handelsregister: Amtsgericht Dortmund A 12812
>
>
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Georg Heeg
Andres,

Certainly it can't but for this purpose 1.0e-13 is a close enough float. By
the way, it also can't be represented as Double, as 1/3 can't be represented
as a decimal.

The point Karsten is making is:

0.3d roundTo: 0.1 should not become a Float, but a Double as 0.3d + 0.1 is a
Double.

Yes, I also know that 1.0e-13 asDouble is 1.0000000502143d-13

Georg

Georg Heeg eK, Dortmund und Köthen, HR Dortmund A 12812
Wallstraße 22, 06366 Köthen
Tel. +49-3496-214328, Fax +49-3496-214712


-----Ursprüngliche Nachricht-----
Von: [hidden email] [mailto:[hidden email]] Im Auftrag
von Andres Valloud
Gesendet: Montag, 11. August 2014 18:09
An: Visualworks Mailing List
Betreff: Re: [vwnc] Floats and Doubles

That's going to be hard to manage.  To begin with, 0.0000000000001 is not
representable as a floating point value.

On 8/11/14 8:45 , Karsten Kusche wrote:

> I’ve just come across the following scenario:
>
> 0.123456789123456d roundTo: 0.0000000000001
>
> i’d expected the result to be around 0.1234567891234.
> what actually happens is that 0.0000000000001 is a represented as a
> float, so the result is again a float, which is 0.123457
>
> Why is it that Float is still the default class for floating-point
> kind of numbers and not Double. And why is the class not automatically
> changed to something with higher precision like it is for Integers?
> Currently it seems that if you really need to use Double precision,
> you need to make sure that every literal number with a „." also has a
> „d“ at the end. And then you need to have tons of tests that make sure
> the results are as expected, which is even less fun, considering the
> lack of comparability in floating-point arithmetics in general.
>
> And then you need to remember that for the next times you or someone
> else needs to work on the code again.
>
> Kind Regards
> Karsten
>
>
> --
> Karsten Kusche - Dipl. Inf. (FH) - [hidden email] Georg Heeg eK -
> Köthen
> Handelsregister: Amtsgericht Dortmund A 12812
>
>
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Andres Valloud-4
I'm not sure about that.  I could see how an argument could be made that
roundTo: is meant to round to a certain precision.  If the certain
precision is of class X, why shouldn't the result be of class X too?

On 8/11/14 9:24 , Georg Heeg wrote:

> Andres,
>
> Certainly it can't but for this purpose 1.0e-13 is a close enough float. By
> the way, it also can't be represented as Double, as 1/3 can't be represented
> as a decimal.
>
> The point Karsten is making is:
>
> 0.3d roundTo: 0.1 should not become a Float, but a Double as 0.3d + 0.1 is a
> Double.
>
> Yes, I also know that 1.0e-13 asDouble is 1.0000000502143d-13
>
> Georg
>
> Georg Heeg eK, Dortmund und Köthen, HR Dortmund A 12812
> Wallstraße 22, 06366 Köthen
> Tel. +49-3496-214328, Fax +49-3496-214712
>
>
> -----Ursprüngliche Nachricht-----
> Von: [hidden email] [mailto:[hidden email]] Im Auftrag
> von Andres Valloud
> Gesendet: Montag, 11. August 2014 18:09
> An: Visualworks Mailing List
> Betreff: Re: [vwnc] Floats and Doubles
>
> That's going to be hard to manage.  To begin with, 0.0000000000001 is not
> representable as a floating point value.
>
> On 8/11/14 8:45 , Karsten Kusche wrote:
>> I've just come across the following scenario:
>>
>> 0.123456789123456d roundTo: 0.0000000000001
>>
>> i'd expected the result to be around 0.1234567891234.
>> what actually happens is that 0.0000000000001 is a represented as a
>> float, so the result is again a float, which is 0.123457
>>
>> Why is it that Float is still the default class for floating-point
>> kind of numbers and not Double. And why is the class not automatically
>> changed to something with higher precision like it is for Integers?
>> Currently it seems that if you really need to use Double precision,
>> you need to make sure that every literal number with a "." also has a
>> "d" at the end. And then you need to have tons of tests that make sure
>> the results are as expected, which is even less fun, considering the
>> lack of comparability in floating-point arithmetics in general.
>>
>> And then you need to remember that for the next times you or someone
>> else needs to work on the code again.
>>
>> Kind Regards
>> Karsten
>>
>>
>> --
>> Karsten Kusche - Dipl. Inf. (FH) - [hidden email] Georg Heeg eK -
>> Köthen
>> Handelsregister: Amtsgericht Dortmund A 12812
>>
>>
>>
>> _______________________________________________
>> vwnc mailing list
>> [hidden email]
>> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Paul Baumann
It is customary (if not standard) Smalltalk behavior that the result of an operation is of the highest #generality. As Georg showed, the sloppy/IEEE #asDouble conversion will make that difficult. Issues like that have plagued VW since efforts to conform to IEEE standards (without compensation for where that original standard falls short like conversion, rounding, and truncation). As discussed many times before, #asDouble should not answer precision that did not exist from the maximum precision of the float (1.0e-13 asDouble should answer 1.0d-13 rather than 1.0000000502143d-13). #roundTo: should answer with the highest #generality. I recall when VW would be better than C when it came to using floats; now we efficiently get the wrong answer for some operations.

Paul Baumann


-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Andres Valloud
Sent: Monday, August 11, 2014 13:28
To: 'Visualworks Mailing List'
Subject: Re: [vwnc] Floats and Doubles

I'm not sure about that.  I could see how an argument could be made that
roundTo: is meant to round to a certain precision.  If the certain precision is of class X, why shouldn't the result be of class X too?

On 8/11/14 9:24 , Georg Heeg wrote:

> Andres,
>
> Certainly it can't but for this purpose 1.0e-13 is a close enough
> float. By the way, it also can't be represented as Double, as 1/3
> can't be represented as a decimal.
>
> The point Karsten is making is:
>
> 0.3d roundTo: 0.1 should not become a Float, but a Double as 0.3d +
> 0.1 is a Double.
>
> Yes, I also know that 1.0e-13 asDouble is 1.0000000502143d-13
>
> Georg
>
> Georg Heeg eK, Dortmund und Köthen, HR Dortmund A 12812 Wallstraße 22,
> 06366 Köthen Tel. +49-3496-214328, Fax +49-3496-214712
>
>
> -----Ursprüngliche Nachricht-----
> Von: [hidden email] [mailto:[hidden email]] Im
> Auftrag von Andres Valloud
> Gesendet: Montag, 11. August 2014 18:09
> An: Visualworks Mailing List
> Betreff: Re: [vwnc] Floats and Doubles
>
> That's going to be hard to manage.  To begin with, 0.0000000000001 is
> not representable as a floating point value.
>
> On 8/11/14 8:45 , Karsten Kusche wrote:
>> I've just come across the following scenario:
>>
>> 0.123456789123456d roundTo: 0.0000000000001
>>
>> i'd expected the result to be around 0.1234567891234.
>> what actually happens is that 0.0000000000001 is a represented as a
>> float, so the result is again a float, which is 0.123457
>>
>> Why is it that Float is still the default class for floating-point
>> kind of numbers and not Double. And why is the class not
>> automatically changed to something with higher precision like it is for Integers?
>> Currently it seems that if you really need to use Double precision,
>> you need to make sure that every literal number with a "." also has a
>> "d" at the end. And then you need to have tons of tests that make
>> sure the results are as expected, which is even less fun, considering
>> the lack of comparability in floating-point arithmetics in general.
>>
>> And then you need to remember that for the next times you or someone
>> else needs to work on the code again.
>>
>> Kind Regards
>> Karsten
>>
>>
>> --
>> Karsten Kusche - Dipl. Inf. (FH) - [hidden email] Georg Heeg eK -
>> Köthen
>> Handelsregister: Amtsgericht Dortmund A 12812
>>
>>
>>
>> _______________________________________________
>> vwnc mailing list
>> [hidden email]
>> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

This message may contain confidential information and is intended for specific recipients unless explicitly noted otherwise. If you have reason to believe you are not an intended recipient of this message, please delete it and notify the sender. This message may not represent the opinion of Intercontinental Exchange, Inc. (ICE), its subsidiaries or affiliates, and does not constitute a contract or guarantee. Unencrypted electronic mail is not secure and the recipient of this message is expected to provide safeguards from viruses and pursue alternate means of communication where privacy or a binding message is desired.

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Martin McClure-5
Just ran across this thread again...

On 08/11/2014 01:09 PM, Paul Baumann wrote:
> It is customary (if not standard) Smalltalk behavior that the result of an operation is of the highest #generality.

True. *And* standard (as in the ANSI Smalltalk standard). Karsten's
example shows that VW's implementation of #roundTo: is very clearly in
conflict with section 5.6.2.32 of the standard.

The ANSI behavior would be to convert the 32-bit float argument to a
64-bit float, then do the rounding. And the answer when you do that is
close to (though not equal to) what you get if you start with
0.0000000000001d0.

So this is a bug, I believe.


> (1.0e-13 asDouble should answer 1.0d-13 rather than 1.0000000502143d-13).

Most of this discrepancy is the result of another bug in VW, where
parsing '1.0e-13' yields a Float that is one ULP greater than what it
should be. Part of it is that 0.0000000000001 is not precisely
representable in either a 32-bit float or a 64-bit float, but the 64-bit
float can be closer, and when converting from 32 to 64 bits the system
can't know what value you meant, so it leaves the value the same.

But I should explain more thoroughly, since floats are widely misunderstood.

Taking a step back and looking at what a float is...
A binary floating-point number is a compact way of storing a limited
form of a fraction. The numerator is constrained to be an integer within
a certain range. The denominator is constrained to be a power of two,
within some defined range. The ranges are wider for 64-bit floats than
for 32-bit floats, but they are otherwise the same. The limitations on
numerator and denominator values means that not every fraction can be
represented as a float. Floating-point operations, when done correctly,
round to the nearest representable fraction.

0.0000000000001 as an exact fraction, is 1/10000000000000. This fraction
is not precisely representable as a float, so it should be rounded to
the fraction

14757395 / 16r80000000000000000

whose precise decimal representation (yes, this is exact) is

0.0000000000000999999982451670044181213370393379591405391693115234375

As you can see, it's a little low. The error is
 0.0000000000000999999982451670044181213370393379591405391693115234375
minus
 0.0000000000001000000000000000000000000000000000000000000000000000000
equals
-0.0000000000000000000017548329955818786629606620408594608306884765625

But the next higher representable float encodes the fraction

14757396 / 16r80000000000000000

which in decimal is

0.00000000000010000000502143058245252404958591796457767486572265625

which is too high by

 0.00000000000000000000502143058245252404958591796457767486572265625

Let's compare those error numbers next to each other

 0.00000000000000000000502143058245252404958591796457767486572265625
-0.0000000000000000000017548329955818786629606620408594608306884765625

It's clear that the lower representation is closer to the desired value,
and should be the actual value you get from 1.0e-13. However, VW gives
you the higher value when you parse '1.0e-13', due to errors in the
Fraction-to-Float conversion. This is the bug I referred to above.

Even if that bug were not present, though, when we send our Float
#asDouble, though, all we have is the value

14757395 / 16r80000000000000000

This could be the exact value desired, or it could have been rounded
from 1.0e-13, or it could be the rounded result of some computation
whose precise result was anywhere between

14757394.500000...001 / 16r80000000000000000
and
14757395.499999...999 / 16r80000000000000000

Making #asDouble answer the 64-bit float that is closest to
0.0000000000001 would be more accurate in some cases, less accurate in
others. So #asDouble just answers the number in the middle of that
range, the double which represents the same fraction that the 32-bit
float represented. (The fractions that can be represented by 64-bit
floats are a superset of the fractions that can be represented by 32-bit
floats.)

1.0d-13 should give the fraction

3961408125713217 / 16r800000000000000000000000

or in decimal

0.00000000000010000000000000000303737455634003709136034716842278413651001756079494953155517578125

VW gets this conversion right, as it happens. I haven't looked deeply
into why.


Converting from 32-bit to 64-bit does not change the value.

1.0e-13 asDouble gives the a Double encoding the fraction

14757395 / 16r80000000000000000

as expected.


Regards,

-Martin
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Nicolas Cellier
Martin McClure <martin.mcclure <at> gemtalksystems.com> writes:

>
> Just ran across this thread again...
>
> On 08/11/2014 01:09 PM, Paul Baumann wrote:
> > It is customary (if not standard) Smalltalk behavior that the result of
an operation is of the highest

> #generality.
>
> True. *And* standard (as in the ANSI Smalltalk standard). Karsten's
> example shows that VW's implementation of #roundTo: is very clearly in
> conflict with section 5.6.2.32 of the standard.
>
> The ANSI behavior would be to convert the 32-bit float argument to a
> 64-bit float, then do the rounding. And the answer when you do that is
> close to (though not equal to) what you get if you start with
> 0.0000000000001d0.
>
> So this is a bug, I believe.
>
> > (1.0e-13 asDouble should answer 1.0d-13 rather than 1.0000000502143d-13).
>
> Most of this discrepancy is the result of another bug in VW, where
> parsing '1.0e-13' yields a Float that is one ULP greater than what it
> should be. Part of it is that 0.0000000000001 is not precisely
> representable in either a 32-bit float or a 64-bit float, but the 64-bit
> float can be closer, and when converting from 32 to 64 bits the system
> can't know what value you meant, so it leaves the value the same.
>

+1 to all what Martin said
All I have to add is:

1) if you install SYSBUG-FloatConversion and SYSEXT-NumberParser from
public-store, then you can correctly parse 1.0e-13 or any other float double
(the parser will return the nearest Float/Double to the decimal Fraction
1/10000000000000)

There is also a SYSEXT-NumberPrinter that will print the shortest decimal
representation that would be correctly rounded to the same Float/Double

2) if you pick implementation of asMinimalDecimalFraction from Pharo, then
you'll be able to magically get what you expect:

0.1e-13 asMinimalDecimalFraction asDouble = 1.0d-13

Getting the minimal decimal fraction that would be correctly rounded to the
same Float/Double is exactly the same problem as printing the shortest
decimal representation and we have well known public algorithms to do this, like

Robert G. Burger and R. Kent Dybvig
Printing Floating Point Numbers Quickly and Accurately
ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation
June 1996.
http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf

Last point, 5^13 < 2^53 so it fits in a Double, thus 1.0d-13 is evaluated as
the ratio of a numerator 1 and denominator 10^13 which are exactly
representable in Double, and by virtue of IEE754 the operations * + - / and
sqrt will answer the nearest Float/Double to the exact result (as if the
result was first evaluated with infinite precision, then rounded to the
nearest representable value). This is why 1.0d-13 gets correctly rounded.

But 5^13 > 2^24 so it does not fit in a Float, thus there are two inexact
operations (think that 5^3 is near 2^7, so 5^13 is near 2^30 - or just
evaluate (5 raisedTo: 13) highBit ).
When we have more than one inexact operation, there is not any guaranty to
get the correctly rounded result, it might work or it might not...



_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Floats and Doubles

Andres Valloud-4
See also the dragon4 algorithm of ca. 2004 by GLS et al, and the grisu3
algorithm by Florian Loitsch of 2010.

On 9/30/14 13:19 , nicolas cellier wrote:

> Martin McClure <martin.mcclure <at> gemtalksystems.com> writes:
>
>>
>> Just ran across this thread again...
>>
>> On 08/11/2014 01:09 PM, Paul Baumann wrote:
>>> It is customary (if not standard) Smalltalk behavior that the result of
> an operation is of the highest
>> #generality.
>>
>> True. *And* standard (as in the ANSI Smalltalk standard). Karsten's
>> example shows that VW's implementation of #roundTo: is very clearly in
>> conflict with section 5.6.2.32 of the standard.
>>
>> The ANSI behavior would be to convert the 32-bit float argument to a
>> 64-bit float, then do the rounding. And the answer when you do that is
>> close to (though not equal to) what you get if you start with
>> 0.0000000000001d0.
>>
>> So this is a bug, I believe.
>>
>>> (1.0e-13 asDouble should answer 1.0d-13 rather than 1.0000000502143d-13).
>>
>> Most of this discrepancy is the result of another bug in VW, where
>> parsing '1.0e-13' yields a Float that is one ULP greater than what it
>> should be. Part of it is that 0.0000000000001 is not precisely
>> representable in either a 32-bit float or a 64-bit float, but the 64-bit
>> float can be closer, and when converting from 32 to 64 bits the system
>> can't know what value you meant, so it leaves the value the same.
>>
>
> +1 to all what Martin said
> All I have to add is:
>
> 1) if you install SYSBUG-FloatConversion and SYSEXT-NumberParser from
> public-store, then you can correctly parse 1.0e-13 or any other float double
> (the parser will return the nearest Float/Double to the decimal Fraction
> 1/10000000000000)
>
> There is also a SYSEXT-NumberPrinter that will print the shortest decimal
> representation that would be correctly rounded to the same Float/Double
>
> 2) if you pick implementation of asMinimalDecimalFraction from Pharo, then
> you'll be able to magically get what you expect:
>
> 0.1e-13 asMinimalDecimalFraction asDouble = 1.0d-13
>
> Getting the minimal decimal fraction that would be correctly rounded to the
> same Float/Double is exactly the same problem as printing the shortest
> decimal representation and we have well known public algorithms to do this, like
>
> Robert G. Burger and R. Kent Dybvig
> Printing Floating Point Numbers Quickly and Accurately
> ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation
> June 1996.
> http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
>
> Last point, 5^13 < 2^53 so it fits in a Double, thus 1.0d-13 is evaluated as
> the ratio of a numerator 1 and denominator 10^13 which are exactly
> representable in Double, and by virtue of IEE754 the operations * + - / and
> sqrt will answer the nearest Float/Double to the exact result (as if the
> result was first evaluated with infinite precision, then rounded to the
> nearest representable value). This is why 1.0d-13 gets correctly rounded.
>
> But 5^13 > 2^24 so it does not fit in a Float, thus there are two inexact
> operations (think that 5^3 is near 2^7, so 5^13 is near 2^30 - or just
> evaluate (5 raisedTo: 13) highBit ).
> When we have more than one inexact operation, there is not any guaranty to
> get the correctly rounded result, it might work or it might not...
>
>
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc