<div dir="ltr"><div><div><div>Well, that's what I'm fighting against: looking good.<br></div><div>The good looking float are putting plenty of traps on our path, and it's better to know about it.<br>I say that it's impossible to maintain the illusion of good looking and friendly float, and in that case it's better to tell the awfull truth.<br>
</div>The changes in Squeak/Pharo are here to un-learn what we thought about decimal numbers, or more accurately to learn that these rules don't apply exactly to Float.</div><div><br></div>Beside, in most languages, if you round the float/double 0.995 to 2 digits - either by a printf or another operation like round(0.995 , 2) - you'll get 0.99 not 1.00.<br>
<br></div><div>Nicolas<br></div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/3/29 Louis LaBrunda <span dir="ltr"><<a href="mailto:Lou@keystone-software.com" target="_blank">Lou@keystone-software.com</a>></span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Nicolas,<br>
<br>
Sorry to be getting back to this so late. I take back what I said about<br>
asTrueFraction. I'm sure it is fine. But I think I question its use in<br>
this case.<br>
<br>
This all started when Stéphane said this:<br>
<div class="im"><br>
0.995 printShowingDecimalPlaces: 2 ==> '1.00'<br>
<br>
</div>was wrong and I didn't think so.<br>
<br>
When one uses a method like printShowingDecimalPlaces: one expects (maybe<br>
there is some other similar method that one should expect this) the result<br>
to look good (yes that is very subjective) but I would say looking good is<br>
more important than being accurate. Yes, that is an admission that<br>
asTrueFraction is the accurate way to convert floats. Looking good would<br>
mean rounded nicely.<br>
<br>
Maybe I'm expecting printShowingDecimalPlaces: to be something it isn't<br>
intended to be but I don't see any other similar method that would perform<br>
the pretty way.<br>
<br>
Lou<br>
<div class="HOEnZb"><div class="h5"><br>
On Tue, 26 Mar 2013 22:11:41 +0100, Nicolas Cellier<br>
<<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>> wrote:<br>
<br>
>2013/3/26 Louis LaBrunda <<a href="mailto:Lou@keystone-software.com">Lou@keystone-software.com</a>>:<br>
>> Hi Nicolas,<br>
>><br>
>> snip...<br>
>><br>
>>>> In VA Smalltalk:<br>
>>>><br>
>>>> 0.995 = 0.995s3 => true<br>
>>>> 0.995 < 0.995s3 => false<br>
>><br>
>>>This is a default st80 behavior which converts minimumGenerality<br>
>>>number to maximumGenerality.<br>
>><br>
>> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when<br>
>> compared to 0.995s3 is equal. And when 0.995s3 is converted to float that<br>
>> float compares equal to 0.995.<br>
>><br>
>>>Maybe some of these conventions are hardwired in VM, I don't know, but<br>
>>>in other dialects it's handled at image side.<br>
>><br>
>>>The idea was this one: if you perform an operation between an inexact<br>
>>>value and an exact value, the result is inexact.<br>
>>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.<br>
>>>Thus Float got a higher generality.<br>
>><br>
>> This would imply that one should convert the ScaledDecimal to a Float<br>
>> before the compare. But as above that would not change things (I think<br>
>> maybe because VA uses 8 byte floats).<br>
>><br>
>> This is from Squeak:<br>
>><br>
>> 0.995s3 asFloat<br>
>> 0.995<br>
>><br>
>> 0.995s3 asFloat = 0.995<br>
>> true<br>
>><br>
>> 0.995 asScaledDecimal<br>
>> 0.99499999s8<br>
>><br>
>> (995 / 1000) asScaledDecimal<br>
>> 0.995s3<br>
>><br>
>> 0.995 asTrueFraction asScaledDecimal<br>
>> 0.99499999999999999555910790149937383830547332763671875s53<br>
>><br>
>> (0.995 * 1000000000) asScaledDecimal / 1000000000<br>
>> 0.99500000s8<br>
>><br>
><br>
>Yep, but (0.995 * 1000000000) is inexact...<br>
>You can check that (0.995 * 1000000000) ~~ (0.995 asFraction * 1000000000)<br>
><br>
>You cannot rely on results of any such inexact calculus, or you'll be<br>
>building on sand.<br>
><br>
>> 0.995 * 1000000000<br>
>> 9.95e8<br>
>><br>
>> Sorry, but I have run out of time to play at the moment. So, I will just<br>
>> throw a thought out there. I think there may be a problem with<br>
>> asTrueFraction. Which if implemented differently might not make 0.995 <<br>
>> 0.995s3.<br>
>><br>
><br>
>Well I doubt, but I'm all ears ;)<br>
><br>
>(0.995 asFraction storeStringBase: 2)<br>
>-> '(2r11111110101110000101000111101011100001010001111010111/2r100000000000000000000000000000000000000000000000000000)'.<br>
><br>
>(0.995 successor) asFraction storeStringBase: 2<br>
>-> '(2r11111110101110000101000111101011100001010001111011/2r100000000000000000000000000000000000000000000000000)'<br>
>-> '(2r11111110101110000101000111101011100001010001111011000/2r100000000000000000000000000000000000000000000000000000)'.<br>
><br>
>(0.995 predecessor) asFraction storeStringBase: 2<br>
>-> '(2r1111111010111000010100011110101110000101000111101011/2r10000000000000000000000000000000000000000000000000000)'<br>
>-> '(2r11111110101110000101000111101011100001010001111010110/2r100000000000000000000000000000000000000000000000000000)'.<br>
><br>
>0.995 ulp asFraction storeStringBase: 2<br>
>-> '(2r1/2r100000000000000000000000000000000000000000000000000000)'.<br>
><br>
>(995/1000 - 0.995 asFraction) / 0.995 ulp<br>
>-> 0.04.<br>
><br>
>(995/1000 - 0.995 successor asFraction) / 0.995 ulp<br>
>-> -0.96.<br>
><br>
>(995/1000 - 0.995 successor asFraction) / 0.995 ulp<br>
>-> 1.04.<br>
><br>
>and numerator/denominator have this property:<br>
><br>
>2r11111110101110000101000111101011100001010001111010111 highBit<br>
>-> 53.<br>
>2r100000000000000000000000000000000000000000000000000000 highBit<br>
>-> 54.<br>
><br>
>So, 53 bits of significand, a power of two on denominator, that sounds<br>
>like a correct Float, slightly smaller than 1.<br>
>Next significand and previous significand are both further of<br>
>(995/1000) than 0.995 is.<br>
>0.995 is closest Float to 995/1000 and is smaller than 995/1000, no doubt.<br>
><br>
>Nicolas<br>
><br>
>>>The idea behind Squeak change is that every Float has an exact value<br>
>>>(asTrueFraction).<br>
>>>Since we have only two possible answers true/false for comparison, and<br>
>>>no maybe or dontKnow, it makes sense to compare the exact value.<br>
>>>This reduces the number of paradoxal equalities<br>
>>><br>
>>>| a b c |<br>
>>>a := 1 << Float precision.<br>
>>>b := a + 1.<br>
>>>c := a asFloat.<br>
>>>{<br>
>>>c = b.<br>
>>>c = a.<br>
>>>a = b.<br>
>>>}<br>
>>><br>
>>>In VW and VA, the first two are true, the last is false, which<br>
>>>suggests that = is not an equivalence relation.<br>
>>>In Squeak, only the second one is true.<br>
>>><br>
>>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...<br>
>>>This is still true in Squeak, not in VA/VW/st80.<br>
>>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).<br>
>>><br>
>>><br>
>>>> I think in VA Smalltalk there is some VM magic going on that makes the<br>
>>>> above work the way it does. The #= and #< of Float are implemented in a<br>
>>>> primitive. I guess when converting the '0.995' string to a float a little<br>
>>>> is lost and that would make it less than 0.995s3 but there is a lot of code<br>
>>>> floating around (sorry about the puns) to make floats look better. In that<br>
>>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)<br>
>>>> to show '1.00' and not '0.99'.<br>
>>>><br>
>>><br>
>>>No, people should not rely on such behavior with Floats, because<br>
>>>sooner than later they will be bitten.<br>
>>>We cannot cheat very long with this kind of assumptions.<br>
>>>My POV is that it is better to educate about false expectations with<br>
>>>Float, and that's the main benefit of (1/10) ~= 0.1.<br>
>>><br>
>>>I would add that such print policy is not the behaviour of every other<br>
>>>language I know of.<br>
>>><br>
>>>printf( "%.2f",0.995)<br>
>>>-> 0.99<br>
>>><br>
>>>Because libm are carefully written nowdays and other languages<br>
>>>libraries are either built over libm or much more careful than<br>
>>>Smalltalk were (that mostly means more recent).<br>
>>><br>
>>>> Anyway, we should try not to use floats without a very, very good reason.<br>
>>>> Like we have to send them outside of Smalltalk or we really need the speed<br>
>>>> or decimals and fractions take up too much memory. But then we must live<br>
>>>> with their inaccuracies and display mess.<br>
>>>><br>
>>><br>
>>>Good advice, let's put those expectations on decimal fractions<br>
>>>(ScaledDecimal/FixedPoint) or general Fraction.<br>
>>><br>
>>>> I have an untested theory that fractions can be close in speed to floats<br>
>>>> because divisions (that are expensive) can be pushed to the end of a<br>
>>>> computation because with fractions they are multiplies.<br>
>>>><br>
>>>> Lou<br>
>>><br>
>>>Why not, but huge numerators and denominators are not cheap compared<br>
>>>to Float operations.<br>
>>>OK reducing the fraction is the expensive part, but how does the cost<br>
>>>grow versus the length of operands?<br>
>>><br>
>>>Also some geometric operations are not even possible on Q (hypot) so<br>
>>>you might soon need AlgebraicNumber.<br>
>>>And Smalltalk is also about graphics and geometry.<br>
>>><br>
>>>Nicolas<br>
>>><br>
>>>> -----------------------------------------------------------<br>
>>>> Louis LaBrunda<br>
>>>> Keystone Software Corp.<br>
>>>> SkypeMe callto://PhotonDemon<br>
>>>> mailto:<a href="mailto:Lou@Keystone-Software.com">Lou@Keystone-Software.com</a> <a href="http://www.Keystone-Software.com" target="_blank">http://www.Keystone-Software.com</a><br>
>>>><br>
>>>><br>
>>><br>
>> -----------------------------------------------------------<br>
>> Louis LaBrunda<br>
>> Keystone Software Corp.<br>
>> SkypeMe callto://PhotonDemon<br>
>> mailto:<a href="mailto:Lou@Keystone-Software.com">Lou@Keystone-Software.com</a> <a href="http://www.Keystone-Software.com" target="_blank">http://www.Keystone-Software.com</a><br>
>><br>
>><br>
><br>
-----------------------------------------------------------<br>
Louis LaBrunda<br>
Keystone Software Corp.<br>
SkypeMe callto://PhotonDemon<br>
mailto:<a href="mailto:Lou@Keystone-Software.com">Lou@Keystone-Software.com</a> <a href="http://www.Keystone-Software.com" target="_blank">http://www.Keystone-Software.com</a><br>
<br>
<br>
</div></div></blockquote></div><br></div>