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 |
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 |
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: > Ive just come across the following scenario: > > 0.123456789123456d roundTo: 0.0000000000001 > > id 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 |
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 |
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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |