[squeak-dev] Re: The joys (or not) of floating point numbers

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Tue Mar 26 09:37:52 UTC 2013


2013/3/26 glenpaling <slp5591 at me.com>:
> tim Rowledge wrote
>> As a side-effect of running the SpaceTally code I had to look at
>> implementations of #roundTo: because the output was bizarrely formatted.
>>
>> It turns out that for several of the percentage values calculated by -
>> percent := s spaceForInstances*100.0/totalInstSpace roundTo: 0.1.
>> - we get decidedly not numbers that match what we probably think we should
>> get. For example
>> 28846801 *100.0 /  53172599 ->  54.25125260474855
>> BUT
>> 54.25125260474855 roundTo: 0.1 -> 54.300000000000004
>> What? That's not even correct, let alone rounded to the requested
>> precision.
>>
>> Who is a numerics aficionado?
>>
>> tim
>> --
>> tim Rowledge;
>
>> tim@
>
>> ; http://www.rowledge.org/tim
>> Managing programmers is like herding cats.
>
> roundTo: rounds to a quantum so:
>
> 100 roundTo: 8 -> 104
> 100 roundTo: 0.8 -> 100
> 100 roundTo: (Float pi) -> 100.53096491487338
>
> For printing you want:
> 54.25125260474855 printShowingDecimalPlaces: 1 -> '54.3'
>
>

Yep, it's because we now tell the awfull truth about floats.

0.1 = (1/10) -> false. "it's not exactly 1/10"
0.1 = (1/10.0) -> true. "yes, it's the same approximation, with same
rounding error"

#(successor predecessor) allSatisfy: [:neighbourhood |
  ((0.1 perform: neighbourhood) asFraction - (1/10)) abs >= (0.1
asFraction - (1/10)) abs]. "yes 0.1 is closest float to 1/10"

(0.1 asFraction - (1/10)) / 0.1 ulp -> 0.4. "Yep, 0.4 ulp error is OK,
IEEE 754 ops guaranty +/- 0.5 ulp"

but:
543/10.0 -> 54.3. "sounds good"
543/10.0 = (543/10) -> false. "But inexact, with a single rounding error"
543*0.1-> 54.300000000000004. "this cumulated two rounding errors"

(54.3 asFraction- (543/10)) / 54.3 ulp -> -0.4.
((543*0.1) asFraction- (543/10)) / 54.3 ulp -> 0.6.

So what you want is 543/10, but that's not what roundTo: 0.1 does...

Old 3.X Squeak could maintain the illusion a little longer because it
used to print Floats approximately.
Float>>printString now prints the shortest decimal form that will be
re-interpreted as the same Float, and that's the only thing that
changed.
Every two finite different Float shall have a different print.

Use printShowingDecimalPlaces: as suggested
or round to an exact fraction

54.25125260474855 roundTo: 1/10.
54.25125260474855 roundTo: 0.1s1.

Nicolas

>
> --
> View this message in context: http://forum.world.st/The-joys-or-not-of-floating-point-numbers-tp4678288p4678289.html
> Sent from the Squeak - Dev mailing list archive at Nabble.com.
>


More information about the Squeak-dev mailing list