The joys (or not) of floating point numbers

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

The joys (or not) of floating point numbers

timrowledge
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; [hidden email]; http://www.rowledge.org/tim
Managing programmers is like herding cats.



Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

glenpaling
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; [hidden email]; 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'
Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
2013/3/26 glenpaling <[hidden email]>:

> 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.
>

Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Stéphane Rollandin
In my image I have:

precision: aNumber

        | pten |

        self isInfinite ifTrue: [^ self].

        pten := 10 raisedTo: aNumber.
        ^ (pten * self) rounded / pten asFloat


54.25125260474855 precision: 1 ==> 54.3

What do you think of it Nicolas ? Does it make sense ?

Stef

Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
2013/3/26 Stéphane Rollandin <[hidden email]>:

> In my image I have:
>
> precision: aNumber
>
>         | pten |
>
>         self isInfinite ifTrue: [^ self].
>
>         pten := 10 raisedTo: aNumber.
>         ^ (pten * self) rounded / pten asFloat
>
>
> 54.25125260474855 precision: 1 ==> 54.3
>
> What do you think of it Nicolas ? Does it make sense ?
>
> Stef
>

Yes, it's better than roundTo: 0.1.
Pharo has implemented a similar method named #round:
http://code.google.com/p/pharo/issues/detail?id=5590
It's still not perfect because it cumulates two inexact operations:
- one inexact operation in the multiplication pten * self
- one inexact operation in the division / pten

Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
should round to 0.99.

Nicolas

Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Stéphane Rollandin
> It's still not perfect because it cumulates two inexact operations:
> - one inexact operation in the multiplication pten * self
> - one inexact operation in the division / pten
>
> Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
> should round to 0.99.

Thanks. This stuff is really tricky !

Stef


Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Stéphane Rollandin
In reply to this post by Nicolas Cellier
> Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
> should round to 0.99.

.. and I just noticed that

        0.995 printShowingDecimalPlaces: 2   ==>  '1.00'

Do we have a method returning the correct value ?

Stef

Reply | Threaded
Open this post in threaded view
|

The joys (or not) of floating point numbers

Louis LaBrunda
On Tue, 26 Mar 2013 18:32:31 +0100, Stéphane Rollandin
<[hidden email]> wrote:

>> Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
>> should round to 0.99.
>
>.. and I just noticed that
>
> 0.995 printShowingDecimalPlaces: 2   ==>  '1.00'
>
>Do we have a method returning the correct value ?

That looks right to me, because 0.995 was rounded up.

Lou
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com


Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
2013/3/26 Louis LaBrunda <[hidden email]>:

> On Tue, 26 Mar 2013 18:32:31 +0100, Stéphane Rollandin
> <[hidden email]> wrote:
>
>>> Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
>>> should round to 0.99.
>>
>>.. and I just noticed that
>>
>>       0.995 printShowingDecimalPlaces: 2   ==>  '1.00'
>>
>>Do we have a method returning the correct value ?
>
> That looks right to me, because 0.995 was rounded up.
>
> Lou

No it's not, because 0.995 < 0.995s3 so it should be rounded down.
In a recent trunk image, print is OK:
(0.995 printShowingDecimalPlaces: 2) ->  '0.99'

Nicolas


> -----------------------------------------------------------
> Louis LaBrunda
> Keystone Software Corp.
> SkypeMe callto://PhotonDemon
> mailto:[hidden email] http://www.Keystone-Software.com
>
>

Reply | Threaded
Open this post in threaded view
|

The joys (or not) of floating point numbers

Louis LaBrunda
On Tue, 26 Mar 2013 18:59:12 +0100, Nicolas Cellier
<[hidden email]> wrote:

>2013/3/26 Louis LaBrunda <[hidden email]>:
>> On Tue, 26 Mar 2013 18:32:31 +0100, Stéphane Rollandin
>> <[hidden email]> wrote:
>>
>>>> Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
>>>> should round to 0.99.
>>>
>>>.. and I just noticed that
>>>
>>>       0.995 printShowingDecimalPlaces: 2   ==>  '1.00'
>>>
>>>Do we have a method returning the correct value ?
>>
>> That looks right to me, because 0.995 was rounded up.
>>
>> Lou
>
>No it's not, because 0.995 < 0.995s3 so it should be rounded down.
>In a recent trunk image, print is OK:
>(0.995 printShowingDecimalPlaces: 2) ->  '0.99'

In VA Smalltalk:

0.995 = 0.995s3 => true
0.995 < 0.995s3 => false

I think in VA Smalltalk there is some VM magic going on that makes the
above work the way it does.  The #= and #< of Float are implemented in a
primitive.  I guess when converting the '0.995' string to a float a little
is lost and that would make it less than 0.995s3 but there is a lot of code
floating around (sorry about the puns) to make floats look better.  In that
case I would think people would want (0.995 printShowingDecimalPlaces: 2)
to show '1.00' and not '0.99'.

Anyway, we should try not to use floats without a very, very good reason.
Like we have to send them outside of Smalltalk or we really need the speed
or decimals and fractions take up too much memory.  But then we must live
with their inaccuracies and display mess.

I have an untested theory that fractions can be close in speed to floats
because divisions (that are expensive) can be pushed to the end of a
computation because with fractions they are multiplies.

Lou
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com


Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
2013/3/26 Louis LaBrunda <[hidden email]>:

> On Tue, 26 Mar 2013 18:59:12 +0100, Nicolas Cellier
> <[hidden email]> wrote:
>
>>2013/3/26 Louis LaBrunda <[hidden email]>:
>>> On Tue, 26 Mar 2013 18:32:31 +0100, Stéphane Rollandin
>>> <[hidden email]> wrote:
>>>
>>>>> Example (0.995 round: 2) -> 1.00 though 0.995 < (995/1000) so it
>>>>> should round to 0.99.
>>>>
>>>>.. and I just noticed that
>>>>
>>>>       0.995 printShowingDecimalPlaces: 2   ==>  '1.00'
>>>>
>>>>Do we have a method returning the correct value ?
>>>
>>> That looks right to me, because 0.995 was rounded up.
>>>
>>> Lou
>>
>>No it's not, because 0.995 < 0.995s3 so it should be rounded down.
>>In a recent trunk image, print is OK:
>>(0.995 printShowingDecimalPlaces: 2) ->  '0.99'
>
> In VA Smalltalk:
>
> 0.995 = 0.995s3 => true
> 0.995 < 0.995s3 => false
>

This is a default st80 behavior which converts minimumGenerality
number to maximumGenerality.
Maybe some of these conventions are hardwired in VM, I don't know, but
in other dialects it's handled at image side.

The idea was this one: if you perform an operation between an inexact
value and an exact value, the result is inexact.
So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
Thus Float got a higher generality.

The idea behind Squeak change is that every Float has an exact value
(asTrueFraction).
Since we have only two possible answers true/false for comparison, and
no maybe or dontKnow, it makes sense to compare the exact value.
This reduces the number of paradoxal equalities

| a b c |
a := 1 << Float precision.
b := a + 1.
c := a asFloat.
{
c = b.
c = a.
a = b.
}

In VW and VA, the first two are true, the last is false, which
suggests that = is not an equivalence relation.
In Squeak, only the second one is true.

Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
This is still true in Squeak, not in VA/VW/st80.
I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).


> I think in VA Smalltalk there is some VM magic going on that makes the
> above work the way it does.  The #= and #< of Float are implemented in a
> primitive.  I guess when converting the '0.995' string to a float a little
> is lost and that would make it less than 0.995s3 but there is a lot of code
> floating around (sorry about the puns) to make floats look better.  In that
> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
> to show '1.00' and not '0.99'.
>

No, people should not rely on such behavior with Floats, because
sooner than later they will be bitten.
We cannot cheat very long with this kind of assumptions.
My POV is that it is better to educate about false expectations with
Float, and that's the main benefit of (1/10) ~= 0.1.

I would add that such print policy is not the behaviour of every other
language I know of.

printf( "%.2f",0.995)
-> 0.99

Because libm are carefully written nowdays and other languages
libraries are either built over libm or much more careful than
Smalltalk were (that mostly means more recent).

> Anyway, we should try not to use floats without a very, very good reason.
> Like we have to send them outside of Smalltalk or we really need the speed
> or decimals and fractions take up too much memory.  But then we must live
> with their inaccuracies and display mess.
>

Good advice, let's put those expectations on decimal fractions
(ScaledDecimal/FixedPoint) or general Fraction.

> I have an untested theory that fractions can be close in speed to floats
> because divisions (that are expensive) can be pushed to the end of a
> computation because with fractions they are multiplies.
>
> Lou

Why not, but huge numerators and denominators are not cheap compared
to Float operations.
OK reducing the fraction is the expensive part, but how does the cost
grow versus the length of operands?

Also some geometric operations are not even possible on Q (hypot) so
you might soon need AlgebraicNumber.
And Smalltalk is also about graphics and geometry.

Nicolas

> -----------------------------------------------------------
> Louis LaBrunda
> Keystone Software Corp.
> SkypeMe callto://PhotonDemon
> mailto:[hidden email] http://www.Keystone-Software.com
>
>

Reply | Threaded
Open this post in threaded view
|

The joys (or not) of floating point numbers

Louis LaBrunda
Hi Nicolas,

snip...

>> In VA Smalltalk:
>>
>> 0.995 = 0.995s3 => true
>> 0.995 < 0.995s3 => false

>This is a default st80 behavior which converts minimumGenerality
>number to maximumGenerality.

In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
float compares equal to 0.995.

>Maybe some of these conventions are hardwired in VM, I don't know, but
>in other dialects it's handled at image side.

>The idea was this one: if you perform an operation between an inexact
>value and an exact value, the result is inexact.
>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>Thus Float got a higher generality.

This would imply that one should convert the ScaledDecimal to a Float
before the compare.  But as above that would not change things (I think
maybe because VA uses 8 byte floats).

This is from Squeak:

0.995s3 asFloat
 0.995

0.995s3 asFloat = 0.995
 true

0.995 asScaledDecimal
 0.99499999s8

(995 / 1000) asScaledDecimal
 0.995s3

0.995 asTrueFraction asScaledDecimal
 0.99499999999999999555910790149937383830547332763671875s53

(0.995 * 1000000000) asScaledDecimal / 1000000000
 0.99500000s8

0.995 * 1000000000
 9.95e8

Sorry, but I have run out of time to play at the moment.  So, I will just
throw a thought out there.  I think there may be a problem with
asTrueFraction.  Which if implemented differently might not make 0.995 <
0.995s3.

>The idea behind Squeak change is that every Float has an exact value
>(asTrueFraction).
>Since we have only two possible answers true/false for comparison, and
>no maybe or dontKnow, it makes sense to compare the exact value.
>This reduces the number of paradoxal equalities
>
>| a b c |
>a := 1 << Float precision.
>b := a + 1.
>c := a asFloat.
>{
>c = b.
>c = a.
>a = b.
>}
>
>In VW and VA, the first two are true, the last is false, which
>suggests that = is not an equivalence relation.
>In Squeak, only the second one is true.
>
>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>This is still true in Squeak, not in VA/VW/st80.
>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>
>
>> I think in VA Smalltalk there is some VM magic going on that makes the
>> above work the way it does.  The #= and #< of Float are implemented in a
>> primitive.  I guess when converting the '0.995' string to a float a little
>> is lost and that would make it less than 0.995s3 but there is a lot of code
>> floating around (sorry about the puns) to make floats look better.  In that
>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>> to show '1.00' and not '0.99'.
>>
>
>No, people should not rely on such behavior with Floats, because
>sooner than later they will be bitten.
>We cannot cheat very long with this kind of assumptions.
>My POV is that it is better to educate about false expectations with
>Float, and that's the main benefit of (1/10) ~= 0.1.
>
>I would add that such print policy is not the behaviour of every other
>language I know of.
>
>printf( "%.2f",0.995)
>-> 0.99
>
>Because libm are carefully written nowdays and other languages
>libraries are either built over libm or much more careful than
>Smalltalk were (that mostly means more recent).
>
>> Anyway, we should try not to use floats without a very, very good reason.
>> Like we have to send them outside of Smalltalk or we really need the speed
>> or decimals and fractions take up too much memory.  But then we must live
>> with their inaccuracies and display mess.
>>
>
>Good advice, let's put those expectations on decimal fractions
>(ScaledDecimal/FixedPoint) or general Fraction.
>
>> I have an untested theory that fractions can be close in speed to floats
>> because divisions (that are expensive) can be pushed to the end of a
>> computation because with fractions they are multiplies.
>>
>> Lou
>
>Why not, but huge numerators and denominators are not cheap compared
>to Float operations.
>OK reducing the fraction is the expensive part, but how does the cost
>grow versus the length of operands?
>
>Also some geometric operations are not even possible on Q (hypot) so
>you might soon need AlgebraicNumber.
>And Smalltalk is also about graphics and geometry.
>
>Nicolas
>
>> -----------------------------------------------------------
>> Louis LaBrunda
>> Keystone Software Corp.
>> SkypeMe callto://PhotonDemon
>> mailto:[hidden email] http://www.Keystone-Software.com
>>
>>
>
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com


Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
2013/3/26 Louis LaBrunda <[hidden email]>:

> Hi Nicolas,
>
> snip...
>
>>> In VA Smalltalk:
>>>
>>> 0.995 = 0.995s3 => true
>>> 0.995 < 0.995s3 => false
>
>>This is a default st80 behavior which converts minimumGenerality
>>number to maximumGenerality.
>
> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
> compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
> float compares equal to 0.995.
>
>>Maybe some of these conventions are hardwired in VM, I don't know, but
>>in other dialects it's handled at image side.
>
>>The idea was this one: if you perform an operation between an inexact
>>value and an exact value, the result is inexact.
>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>>Thus Float got a higher generality.
>
> This would imply that one should convert the ScaledDecimal to a Float
> before the compare.  But as above that would not change things (I think
> maybe because VA uses 8 byte floats).
>
> This is from Squeak:
>
> 0.995s3 asFloat
>  0.995
>
> 0.995s3 asFloat = 0.995
>  true
>
> 0.995 asScaledDecimal
>  0.99499999s8
>
> (995 / 1000) asScaledDecimal
>  0.995s3
>
> 0.995 asTrueFraction asScaledDecimal
>  0.99499999999999999555910790149937383830547332763671875s53
>
> (0.995 * 1000000000) asScaledDecimal / 1000000000
>  0.99500000s8
>

Yep, but (0.995 * 1000000000) is inexact...
You can check that (0.995 * 1000000000) ~~ (0.995 asFraction * 1000000000)

You cannot rely on results of any such inexact calculus, or you'll be
building on sand.

> 0.995 * 1000000000
>  9.95e8
>
> Sorry, but I have run out of time to play at the moment.  So, I will just
> throw a thought out there.  I think there may be a problem with
> asTrueFraction.  Which if implemented differently might not make 0.995 <
> 0.995s3.
>

Well I doubt, but I'm all ears ;)

(0.995 asFraction storeStringBase: 2)
-> '(2r11111110101110000101000111101011100001010001111010111/2r100000000000000000000000000000000000000000000000000000)'.

(0.995 successor) asFraction storeStringBase: 2
-> '(2r11111110101110000101000111101011100001010001111011/2r100000000000000000000000000000000000000000000000000)'
-> '(2r11111110101110000101000111101011100001010001111011000/2r100000000000000000000000000000000000000000000000000000)'.

(0.995 predecessor) asFraction storeStringBase: 2
-> '(2r1111111010111000010100011110101110000101000111101011/2r10000000000000000000000000000000000000000000000000000)'
-> '(2r11111110101110000101000111101011100001010001111010110/2r100000000000000000000000000000000000000000000000000000)'.

0.995 ulp asFraction storeStringBase: 2
-> '(2r1/2r100000000000000000000000000000000000000000000000000000)'.

(995/1000 - 0.995 asFraction) / 0.995 ulp
-> 0.04.

(995/1000 - 0.995 successor asFraction) / 0.995 ulp
->  -0.96.

(995/1000 - 0.995 successor asFraction) / 0.995 ulp
->  1.04.

and numerator/denominator have this property:

2r11111110101110000101000111101011100001010001111010111 highBit
-> 53.
2r100000000000000000000000000000000000000000000000000000 highBit
-> 54.

So, 53 bits of significand, a power of two on denominator, that sounds
like a correct Float, slightly smaller than 1.
Next significand and previous significand are both further of
(995/1000) than 0.995 is.
0.995 is closest Float to 995/1000 and is smaller than 995/1000, no doubt.

Nicolas

>>The idea behind Squeak change is that every Float has an exact value
>>(asTrueFraction).
>>Since we have only two possible answers true/false for comparison, and
>>no maybe or dontKnow, it makes sense to compare the exact value.
>>This reduces the number of paradoxal equalities
>>
>>| a b c |
>>a := 1 << Float precision.
>>b := a + 1.
>>c := a asFloat.
>>{
>>c = b.
>>c = a.
>>a = b.
>>}
>>
>>In VW and VA, the first two are true, the last is false, which
>>suggests that = is not an equivalence relation.
>>In Squeak, only the second one is true.
>>
>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>>This is still true in Squeak, not in VA/VW/st80.
>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>>
>>
>>> I think in VA Smalltalk there is some VM magic going on that makes the
>>> above work the way it does.  The #= and #< of Float are implemented in a
>>> primitive.  I guess when converting the '0.995' string to a float a little
>>> is lost and that would make it less than 0.995s3 but there is a lot of code
>>> floating around (sorry about the puns) to make floats look better.  In that
>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>>> to show '1.00' and not '0.99'.
>>>
>>
>>No, people should not rely on such behavior with Floats, because
>>sooner than later they will be bitten.
>>We cannot cheat very long with this kind of assumptions.
>>My POV is that it is better to educate about false expectations with
>>Float, and that's the main benefit of (1/10) ~= 0.1.
>>
>>I would add that such print policy is not the behaviour of every other
>>language I know of.
>>
>>printf( "%.2f",0.995)
>>-> 0.99
>>
>>Because libm are carefully written nowdays and other languages
>>libraries are either built over libm or much more careful than
>>Smalltalk were (that mostly means more recent).
>>
>>> Anyway, we should try not to use floats without a very, very good reason.
>>> Like we have to send them outside of Smalltalk or we really need the speed
>>> or decimals and fractions take up too much memory.  But then we must live
>>> with their inaccuracies and display mess.
>>>
>>
>>Good advice, let's put those expectations on decimal fractions
>>(ScaledDecimal/FixedPoint) or general Fraction.
>>
>>> I have an untested theory that fractions can be close in speed to floats
>>> because divisions (that are expensive) can be pushed to the end of a
>>> computation because with fractions they are multiplies.
>>>
>>> Lou
>>
>>Why not, but huge numerators and denominators are not cheap compared
>>to Float operations.
>>OK reducing the fraction is the expensive part, but how does the cost
>>grow versus the length of operands?
>>
>>Also some geometric operations are not even possible on Q (hypot) so
>>you might soon need AlgebraicNumber.
>>And Smalltalk is also about graphics and geometry.
>>
>>Nicolas
>>
>>> -----------------------------------------------------------
>>> Louis LaBrunda
>>> Keystone Software Corp.
>>> SkypeMe callto://PhotonDemon
>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>
>>>
>>
> -----------------------------------------------------------
> Louis LaBrunda
> Keystone Software Corp.
> SkypeMe callto://PhotonDemon
> mailto:[hidden email] http://www.Keystone-Software.com
>
>

Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
2013/3/26 Nicolas Cellier <[hidden email]>:

> 2013/3/26 Louis LaBrunda <[hidden email]>:
>> Hi Nicolas,
>>
>> snip...
>>
>>>> In VA Smalltalk:
>>>>
>>>> 0.995 = 0.995s3 => true
>>>> 0.995 < 0.995s3 => false
>>
>>>This is a default st80 behavior which converts minimumGenerality
>>>number to maximumGenerality.
>>
>> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
>> compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
>> float compares equal to 0.995.
>>
>>>Maybe some of these conventions are hardwired in VM, I don't know, but
>>>in other dialects it's handled at image side.
>>
>>>The idea was this one: if you perform an operation between an inexact
>>>value and an exact value, the result is inexact.
>>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>>>Thus Float got a higher generality.
>>
>> This would imply that one should convert the ScaledDecimal to a Float
>> before the compare.  But as above that would not change things (I think
>> maybe because VA uses 8 byte floats).
>>
>> This is from Squeak:
>>
>> 0.995s3 asFloat
>>  0.995
>>
>> 0.995s3 asFloat = 0.995
>>  true
>>
>> 0.995 asScaledDecimal
>>  0.99499999s8
>>
>> (995 / 1000) asScaledDecimal
>>  0.995s3
>>
>> 0.995 asTrueFraction asScaledDecimal
>>  0.99499999999999999555910790149937383830547332763671875s53
>>
>> (0.995 * 1000000000) asScaledDecimal / 1000000000
>>  0.99500000s8
>>
>
> Yep, but (0.995 * 1000000000) is inexact...
> You can check that (0.995 * 1000000000) ~~ (0.995 asFraction * 1000000000)
>

Oops, I mean (0.995 * 1000000000) ~= (0.995 asFraction * 1000000000)

> You cannot rely on results of any such inexact calculus, or you'll be
> building on sand.
>
>> 0.995 * 1000000000
>>  9.95e8
>>
>> Sorry, but I have run out of time to play at the moment.  So, I will just
>> throw a thought out there.  I think there may be a problem with
>> asTrueFraction.  Which if implemented differently might not make 0.995 <
>> 0.995s3.
>>
>
> Well I doubt, but I'm all ears ;)
>
> (0.995 asFraction storeStringBase: 2)
> -> '(2r11111110101110000101000111101011100001010001111010111/2r100000000000000000000000000000000000000000000000000000)'.
>
> (0.995 successor) asFraction storeStringBase: 2
> -> '(2r11111110101110000101000111101011100001010001111011/2r100000000000000000000000000000000000000000000000000)'
> -> '(2r11111110101110000101000111101011100001010001111011000/2r100000000000000000000000000000000000000000000000000000)'.
>
> (0.995 predecessor) asFraction storeStringBase: 2
> -> '(2r1111111010111000010100011110101110000101000111101011/2r10000000000000000000000000000000000000000000000000000)'
> -> '(2r11111110101110000101000111101011100001010001111010110/2r100000000000000000000000000000000000000000000000000000)'.
>
> 0.995 ulp asFraction storeStringBase: 2
> -> '(2r1/2r100000000000000000000000000000000000000000000000000000)'.
>
> (995/1000 - 0.995 asFraction) / 0.995 ulp
> -> 0.04.
>
> (995/1000 - 0.995 successor asFraction) / 0.995 ulp
> ->  -0.96.
>
> (995/1000 - 0.995 successor asFraction) / 0.995 ulp
> ->  1.04.
>
> and numerator/denominator have this property:
>
> 2r11111110101110000101000111101011100001010001111010111 highBit
> -> 53.
> 2r100000000000000000000000000000000000000000000000000000 highBit
> -> 54.
>
> So, 53 bits of significand, a power of two on denominator, that sounds
> like a correct Float, slightly smaller than 1.
> Next significand and previous significand are both further of
> (995/1000) than 0.995 is.
> 0.995 is closest Float to 995/1000 and is smaller than 995/1000, no doubt.
>
> Nicolas
>
>>>The idea behind Squeak change is that every Float has an exact value
>>>(asTrueFraction).
>>>Since we have only two possible answers true/false for comparison, and
>>>no maybe or dontKnow, it makes sense to compare the exact value.
>>>This reduces the number of paradoxal equalities
>>>
>>>| a b c |
>>>a := 1 << Float precision.
>>>b := a + 1.
>>>c := a asFloat.
>>>{
>>>c = b.
>>>c = a.
>>>a = b.
>>>}
>>>
>>>In VW and VA, the first two are true, the last is false, which
>>>suggests that = is not an equivalence relation.
>>>In Squeak, only the second one is true.
>>>
>>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>>>This is still true in Squeak, not in VA/VW/st80.
>>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>>>
>>>
>>>> I think in VA Smalltalk there is some VM magic going on that makes the
>>>> above work the way it does.  The #= and #< of Float are implemented in a
>>>> primitive.  I guess when converting the '0.995' string to a float a little
>>>> is lost and that would make it less than 0.995s3 but there is a lot of code
>>>> floating around (sorry about the puns) to make floats look better.  In that
>>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>>>> to show '1.00' and not '0.99'.
>>>>
>>>
>>>No, people should not rely on such behavior with Floats, because
>>>sooner than later they will be bitten.
>>>We cannot cheat very long with this kind of assumptions.
>>>My POV is that it is better to educate about false expectations with
>>>Float, and that's the main benefit of (1/10) ~= 0.1.
>>>
>>>I would add that such print policy is not the behaviour of every other
>>>language I know of.
>>>
>>>printf( "%.2f",0.995)
>>>-> 0.99
>>>
>>>Because libm are carefully written nowdays and other languages
>>>libraries are either built over libm or much more careful than
>>>Smalltalk were (that mostly means more recent).
>>>
>>>> Anyway, we should try not to use floats without a very, very good reason.
>>>> Like we have to send them outside of Smalltalk or we really need the speed
>>>> or decimals and fractions take up too much memory.  But then we must live
>>>> with their inaccuracies and display mess.
>>>>
>>>
>>>Good advice, let's put those expectations on decimal fractions
>>>(ScaledDecimal/FixedPoint) or general Fraction.
>>>
>>>> I have an untested theory that fractions can be close in speed to floats
>>>> because divisions (that are expensive) can be pushed to the end of a
>>>> computation because with fractions they are multiplies.
>>>>
>>>> Lou
>>>
>>>Why not, but huge numerators and denominators are not cheap compared
>>>to Float operations.
>>>OK reducing the fraction is the expensive part, but how does the cost
>>>grow versus the length of operands?
>>>
>>>Also some geometric operations are not even possible on Q (hypot) so
>>>you might soon need AlgebraicNumber.
>>>And Smalltalk is also about graphics and geometry.
>>>
>>>Nicolas
>>>
>>>> -----------------------------------------------------------
>>>> Louis LaBrunda
>>>> Keystone Software Corp.
>>>> SkypeMe callto://PhotonDemon
>>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>>
>>>>
>>>
>> -----------------------------------------------------------
>> Louis LaBrunda
>> Keystone Software Corp.
>> SkypeMe callto://PhotonDemon
>> mailto:[hidden email] http://www.Keystone-Software.com
>>
>>

Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
In reply to this post by Louis LaBrunda
2013/3/26 Louis LaBrunda <[hidden email]>:

> Hi Nicolas,
>
> snip...
>
>>> In VA Smalltalk:
>>>
>>> 0.995 = 0.995s3 => true
>>> 0.995 < 0.995s3 => false
>
>>This is a default st80 behavior which converts minimumGenerality
>>number to maximumGenerality.
>
> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
> compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
> float compares equal to 0.995.
>
>>Maybe some of these conventions are hardwired in VM, I don't know, but
>>in other dialects it's handled at image side.
>
>>The idea was this one: if you perform an operation between an inexact
>>value and an exact value, the result is inexact.
>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>>Thus Float got a higher generality.
>
> This would imply that one should convert the ScaledDecimal to a Float
> before the compare.  But as above that would not change things (I think
> maybe because VA uses 8 byte floats).
>

No, that's precisely what st80 VW and VA did, convert exact->inexact (asFloat)

And what Squeak/gst/Dolphin/stx don't:
It's better to convert Inexact->exact and perform the comparison
exactly for preserving some of = and < properties.

Having inexact numbers is not a license to spoil accuracy.
If you look at IEEE754 standard, results are always equivalent to an
exact operation followed by a correct rounding (to nearest float, tie
to even in default mode).
Even if they are inexact, we perform the operations as if they were
exact (that's why Float differs from interval calculus).

OK, the exception is transcendental functions which can be very
expensive to compute accurately, so the standard have relaxed the
error to 3 ulp or something like that...
But * + - / sqrt are accurate to 1/2 ulp.

Nicolas

> This is from Squeak:
>
> 0.995s3 asFloat
>  0.995
>
> 0.995s3 asFloat = 0.995
>  true
>
> 0.995 asScaledDecimal
>  0.99499999s8
>
> (995 / 1000) asScaledDecimal
>  0.995s3
>
> 0.995 asTrueFraction asScaledDecimal
>  0.99499999999999999555910790149937383830547332763671875s53
>
> (0.995 * 1000000000) asScaledDecimal / 1000000000
>  0.99500000s8
>
> 0.995 * 1000000000
>  9.95e8
>
> Sorry, but I have run out of time to play at the moment.  So, I will just
> throw a thought out there.  I think there may be a problem with
> asTrueFraction.  Which if implemented differently might not make 0.995 <
> 0.995s3.
>
>>The idea behind Squeak change is that every Float has an exact value
>>(asTrueFraction).
>>Since we have only two possible answers true/false for comparison, and
>>no maybe or dontKnow, it makes sense to compare the exact value.
>>This reduces the number of paradoxal equalities
>>
>>| a b c |
>>a := 1 << Float precision.
>>b := a + 1.
>>c := a asFloat.
>>{
>>c = b.
>>c = a.
>>a = b.
>>}
>>
>>In VW and VA, the first two are true, the last is false, which
>>suggests that = is not an equivalence relation.
>>In Squeak, only the second one is true.
>>
>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>>This is still true in Squeak, not in VA/VW/st80.
>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>>
>>
>>> I think in VA Smalltalk there is some VM magic going on that makes the
>>> above work the way it does.  The #= and #< of Float are implemented in a
>>> primitive.  I guess when converting the '0.995' string to a float a little
>>> is lost and that would make it less than 0.995s3 but there is a lot of code
>>> floating around (sorry about the puns) to make floats look better.  In that
>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>>> to show '1.00' and not '0.99'.
>>>
>>
>>No, people should not rely on such behavior with Floats, because
>>sooner than later they will be bitten.
>>We cannot cheat very long with this kind of assumptions.
>>My POV is that it is better to educate about false expectations with
>>Float, and that's the main benefit of (1/10) ~= 0.1.
>>
>>I would add that such print policy is not the behaviour of every other
>>language I know of.
>>
>>printf( "%.2f",0.995)
>>-> 0.99
>>
>>Because libm are carefully written nowdays and other languages
>>libraries are either built over libm or much more careful than
>>Smalltalk were (that mostly means more recent).
>>
>>> Anyway, we should try not to use floats without a very, very good reason.
>>> Like we have to send them outside of Smalltalk or we really need the speed
>>> or decimals and fractions take up too much memory.  But then we must live
>>> with their inaccuracies and display mess.
>>>
>>
>>Good advice, let's put those expectations on decimal fractions
>>(ScaledDecimal/FixedPoint) or general Fraction.
>>
>>> I have an untested theory that fractions can be close in speed to floats
>>> because divisions (that are expensive) can be pushed to the end of a
>>> computation because with fractions they are multiplies.
>>>
>>> Lou
>>
>>Why not, but huge numerators and denominators are not cheap compared
>>to Float operations.
>>OK reducing the fraction is the expensive part, but how does the cost
>>grow versus the length of operands?
>>
>>Also some geometric operations are not even possible on Q (hypot) so
>>you might soon need AlgebraicNumber.
>>And Smalltalk is also about graphics and geometry.
>>
>>Nicolas
>>
>>> -----------------------------------------------------------
>>> Louis LaBrunda
>>> Keystone Software Corp.
>>> SkypeMe callto://PhotonDemon
>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>
>>>
>>
> -----------------------------------------------------------
> Louis LaBrunda
> Keystone Software Corp.
> SkypeMe callto://PhotonDemon
> mailto:[hidden email] http://www.Keystone-Software.com
>
>

Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
In reply to this post by Nicolas Cellier
2013/3/26 Nicolas Cellier <[hidden email]>:

> 2013/3/26 Nicolas Cellier <[hidden email]>:
>> 2013/3/26 Louis LaBrunda <[hidden email]>:
>>> Hi Nicolas,
>>>
>>> snip...
>>>
>>>>> In VA Smalltalk:
>>>>>
>>>>> 0.995 = 0.995s3 => true
>>>>> 0.995 < 0.995s3 => false
>>>
>>>>This is a default st80 behavior which converts minimumGenerality
>>>>number to maximumGenerality.
>>>
>>> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
>>> compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
>>> float compares equal to 0.995.
>>>
>>>>Maybe some of these conventions are hardwired in VM, I don't know, but
>>>>in other dialects it's handled at image side.
>>>
>>>>The idea was this one: if you perform an operation between an inexact
>>>>value and an exact value, the result is inexact.
>>>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>>>>Thus Float got a higher generality.
>>>
>>> This would imply that one should convert the ScaledDecimal to a Float
>>> before the compare.  But as above that would not change things (I think
>>> maybe because VA uses 8 byte floats).
>>>
>>> This is from Squeak:
>>>
>>> 0.995s3 asFloat
>>>  0.995
>>>
>>> 0.995s3 asFloat = 0.995
>>>  true
>>>
>>> 0.995 asScaledDecimal
>>>  0.99499999s8
>>>
>>> (995 / 1000) asScaledDecimal
>>>  0.995s3
>>>
>>> 0.995 asTrueFraction asScaledDecimal
>>>  0.99499999999999999555910790149937383830547332763671875s53
>>>
>>> (0.995 * 1000000000) asScaledDecimal / 1000000000
>>>  0.99500000s8
>>>
>>
>> Yep, but (0.995 * 1000000000) is inexact...
>> You can check that (0.995 * 1000000000) ~~ (0.995 asFraction * 1000000000)
>>
>
> Oops, I mean (0.995 * 1000000000) ~= (0.995 asFraction * 1000000000)
>

Another way to say it is:

    (0.995 asFraction * 1000000000) numerator highBit > Float precision.

As denominator is a power of two and resulting fraction is reduced,
numerator is odd (or zero).
So the numerator highBit is the number of bits of the significand of
exact result.
So with more bits (binary digits) than a Float significand can
contain, Float result can't be exact.

Nicolas

>> You cannot rely on results of any such inexact calculus, or you'll be
>> building on sand.
>>
>>> 0.995 * 1000000000
>>>  9.95e8
>>>
>>> Sorry, but I have run out of time to play at the moment.  So, I will just
>>> throw a thought out there.  I think there may be a problem with
>>> asTrueFraction.  Which if implemented differently might not make 0.995 <
>>> 0.995s3.
>>>
>>
>> Well I doubt, but I'm all ears ;)
>>
>> (0.995 asFraction storeStringBase: 2)
>> -> '(2r11111110101110000101000111101011100001010001111010111/2r100000000000000000000000000000000000000000000000000000)'.
>>
>> (0.995 successor) asFraction storeStringBase: 2
>> -> '(2r11111110101110000101000111101011100001010001111011/2r100000000000000000000000000000000000000000000000000)'
>> -> '(2r11111110101110000101000111101011100001010001111011000/2r100000000000000000000000000000000000000000000000000000)'.
>>
>> (0.995 predecessor) asFraction storeStringBase: 2
>> -> '(2r1111111010111000010100011110101110000101000111101011/2r10000000000000000000000000000000000000000000000000000)'
>> -> '(2r11111110101110000101000111101011100001010001111010110/2r100000000000000000000000000000000000000000000000000000)'.
>>
>> 0.995 ulp asFraction storeStringBase: 2
>> -> '(2r1/2r100000000000000000000000000000000000000000000000000000)'.
>>
>> (995/1000 - 0.995 asFraction) / 0.995 ulp
>> -> 0.04.
>>
>> (995/1000 - 0.995 successor asFraction) / 0.995 ulp
>> ->  -0.96.
>>
>> (995/1000 - 0.995 successor asFraction) / 0.995 ulp
>> ->  1.04.
>>
>> and numerator/denominator have this property:
>>
>> 2r11111110101110000101000111101011100001010001111010111 highBit
>> -> 53.
>> 2r100000000000000000000000000000000000000000000000000000 highBit
>> -> 54.
>>
>> So, 53 bits of significand, a power of two on denominator, that sounds
>> like a correct Float, slightly smaller than 1.
>> Next significand and previous significand are both further of
>> (995/1000) than 0.995 is.
>> 0.995 is closest Float to 995/1000 and is smaller than 995/1000, no doubt.
>>
>> Nicolas
>>
>>>>The idea behind Squeak change is that every Float has an exact value
>>>>(asTrueFraction).
>>>>Since we have only two possible answers true/false for comparison, and
>>>>no maybe or dontKnow, it makes sense to compare the exact value.
>>>>This reduces the number of paradoxal equalities
>>>>
>>>>| a b c |
>>>>a := 1 << Float precision.
>>>>b := a + 1.
>>>>c := a asFloat.
>>>>{
>>>>c = b.
>>>>c = a.
>>>>a = b.
>>>>}
>>>>
>>>>In VW and VA, the first two are true, the last is false, which
>>>>suggests that = is not an equivalence relation.
>>>>In Squeak, only the second one is true.
>>>>
>>>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>>>>This is still true in Squeak, not in VA/VW/st80.
>>>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>>>>
>>>>
>>>>> I think in VA Smalltalk there is some VM magic going on that makes the
>>>>> above work the way it does.  The #= and #< of Float are implemented in a
>>>>> primitive.  I guess when converting the '0.995' string to a float a little
>>>>> is lost and that would make it less than 0.995s3 but there is a lot of code
>>>>> floating around (sorry about the puns) to make floats look better.  In that
>>>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>>>>> to show '1.00' and not '0.99'.
>>>>>
>>>>
>>>>No, people should not rely on such behavior with Floats, because
>>>>sooner than later they will be bitten.
>>>>We cannot cheat very long with this kind of assumptions.
>>>>My POV is that it is better to educate about false expectations with
>>>>Float, and that's the main benefit of (1/10) ~= 0.1.
>>>>
>>>>I would add that such print policy is not the behaviour of every other
>>>>language I know of.
>>>>
>>>>printf( "%.2f",0.995)
>>>>-> 0.99
>>>>
>>>>Because libm are carefully written nowdays and other languages
>>>>libraries are either built over libm or much more careful than
>>>>Smalltalk were (that mostly means more recent).
>>>>
>>>>> Anyway, we should try not to use floats without a very, very good reason.
>>>>> Like we have to send them outside of Smalltalk or we really need the speed
>>>>> or decimals and fractions take up too much memory.  But then we must live
>>>>> with their inaccuracies and display mess.
>>>>>
>>>>
>>>>Good advice, let's put those expectations on decimal fractions
>>>>(ScaledDecimal/FixedPoint) or general Fraction.
>>>>
>>>>> I have an untested theory that fractions can be close in speed to floats
>>>>> because divisions (that are expensive) can be pushed to the end of a
>>>>> computation because with fractions they are multiplies.
>>>>>
>>>>> Lou
>>>>
>>>>Why not, but huge numerators and denominators are not cheap compared
>>>>to Float operations.
>>>>OK reducing the fraction is the expensive part, but how does the cost
>>>>grow versus the length of operands?
>>>>
>>>>Also some geometric operations are not even possible on Q (hypot) so
>>>>you might soon need AlgebraicNumber.
>>>>And Smalltalk is also about graphics and geometry.
>>>>
>>>>Nicolas
>>>>
>>>>> -----------------------------------------------------------
>>>>> Louis LaBrunda
>>>>> Keystone Software Corp.
>>>>> SkypeMe callto://PhotonDemon
>>>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>>>
>>>>>
>>>>
>>> -----------------------------------------------------------
>>> Louis LaBrunda
>>> Keystone Software Corp.
>>> SkypeMe callto://PhotonDemon
>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>
>>>

Reply | Threaded
Open this post in threaded view
|

The joys (or not) of floating point numbers

Louis LaBrunda
In reply to this post by Nicolas Cellier
Hi Nicolas,

Sorry to be getting back to this so late.  I take back what I said about
asTrueFraction.  I'm sure it is fine.  But I think I question its use in
this case.

This all started when Stéphane said this:

        0.995 printShowingDecimalPlaces: 2   ==>  '1.00'

was wrong and I didn't think so.

When one uses a method like printShowingDecimalPlaces: one expects (maybe
there is some other similar method that one should expect this) the result
to look good (yes that is very subjective) but I would say looking good is
more important than being accurate.  Yes, that is an admission that
asTrueFraction is the accurate way to convert floats.  Looking good would
mean rounded nicely.

Maybe I'm expecting printShowingDecimalPlaces: to be something it isn't
intended to be but I don't see any other similar method that would perform
the pretty way.

Lou

On Tue, 26 Mar 2013 22:11:41 +0100, Nicolas Cellier
<[hidden email]> wrote:

>2013/3/26 Louis LaBrunda <[hidden email]>:
>> Hi Nicolas,
>>
>> snip...
>>
>>>> In VA Smalltalk:
>>>>
>>>> 0.995 = 0.995s3 => true
>>>> 0.995 < 0.995s3 => false
>>
>>>This is a default st80 behavior which converts minimumGenerality
>>>number to maximumGenerality.
>>
>> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
>> compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
>> float compares equal to 0.995.
>>
>>>Maybe some of these conventions are hardwired in VM, I don't know, but
>>>in other dialects it's handled at image side.
>>
>>>The idea was this one: if you perform an operation between an inexact
>>>value and an exact value, the result is inexact.
>>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>>>Thus Float got a higher generality.
>>
>> This would imply that one should convert the ScaledDecimal to a Float
>> before the compare.  But as above that would not change things (I think
>> maybe because VA uses 8 byte floats).
>>
>> This is from Squeak:
>>
>> 0.995s3 asFloat
>>  0.995
>>
>> 0.995s3 asFloat = 0.995
>>  true
>>
>> 0.995 asScaledDecimal
>>  0.99499999s8
>>
>> (995 / 1000) asScaledDecimal
>>  0.995s3
>>
>> 0.995 asTrueFraction asScaledDecimal
>>  0.99499999999999999555910790149937383830547332763671875s53
>>
>> (0.995 * 1000000000) asScaledDecimal / 1000000000
>>  0.99500000s8
>>
>
>Yep, but (0.995 * 1000000000) is inexact...
>You can check that (0.995 * 1000000000) ~~ (0.995 asFraction * 1000000000)
>
>You cannot rely on results of any such inexact calculus, or you'll be
>building on sand.
>
>> 0.995 * 1000000000
>>  9.95e8
>>
>> Sorry, but I have run out of time to play at the moment.  So, I will just
>> throw a thought out there.  I think there may be a problem with
>> asTrueFraction.  Which if implemented differently might not make 0.995 <
>> 0.995s3.
>>
>
>Well I doubt, but I'm all ears ;)
>
>(0.995 asFraction storeStringBase: 2)
>-> '(2r11111110101110000101000111101011100001010001111010111/2r100000000000000000000000000000000000000000000000000000)'.
>
>(0.995 successor) asFraction storeStringBase: 2
>-> '(2r11111110101110000101000111101011100001010001111011/2r100000000000000000000000000000000000000000000000000)'
>-> '(2r11111110101110000101000111101011100001010001111011000/2r100000000000000000000000000000000000000000000000000000)'.
>
>(0.995 predecessor) asFraction storeStringBase: 2
>-> '(2r1111111010111000010100011110101110000101000111101011/2r10000000000000000000000000000000000000000000000000000)'
>-> '(2r11111110101110000101000111101011100001010001111010110/2r100000000000000000000000000000000000000000000000000000)'.
>
>0.995 ulp asFraction storeStringBase: 2
>-> '(2r1/2r100000000000000000000000000000000000000000000000000000)'.
>
>(995/1000 - 0.995 asFraction) / 0.995 ulp
>-> 0.04.
>
>(995/1000 - 0.995 successor asFraction) / 0.995 ulp
>->  -0.96.
>
>(995/1000 - 0.995 successor asFraction) / 0.995 ulp
>->  1.04.
>
>and numerator/denominator have this property:
>
>2r11111110101110000101000111101011100001010001111010111 highBit
>-> 53.
>2r100000000000000000000000000000000000000000000000000000 highBit
>-> 54.
>
>So, 53 bits of significand, a power of two on denominator, that sounds
>like a correct Float, slightly smaller than 1.
>Next significand and previous significand are both further of
>(995/1000) than 0.995 is.
>0.995 is closest Float to 995/1000 and is smaller than 995/1000, no doubt.
>
>Nicolas
>
>>>The idea behind Squeak change is that every Float has an exact value
>>>(asTrueFraction).
>>>Since we have only two possible answers true/false for comparison, and
>>>no maybe or dontKnow, it makes sense to compare the exact value.
>>>This reduces the number of paradoxal equalities
>>>
>>>| a b c |
>>>a := 1 << Float precision.
>>>b := a + 1.
>>>c := a asFloat.
>>>{
>>>c = b.
>>>c = a.
>>>a = b.
>>>}
>>>
>>>In VW and VA, the first two are true, the last is false, which
>>>suggests that = is not an equivalence relation.
>>>In Squeak, only the second one is true.
>>>
>>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>>>This is still true in Squeak, not in VA/VW/st80.
>>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>>>
>>>
>>>> I think in VA Smalltalk there is some VM magic going on that makes the
>>>> above work the way it does.  The #= and #< of Float are implemented in a
>>>> primitive.  I guess when converting the '0.995' string to a float a little
>>>> is lost and that would make it less than 0.995s3 but there is a lot of code
>>>> floating around (sorry about the puns) to make floats look better.  In that
>>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>>>> to show '1.00' and not '0.99'.
>>>>
>>>
>>>No, people should not rely on such behavior with Floats, because
>>>sooner than later they will be bitten.
>>>We cannot cheat very long with this kind of assumptions.
>>>My POV is that it is better to educate about false expectations with
>>>Float, and that's the main benefit of (1/10) ~= 0.1.
>>>
>>>I would add that such print policy is not the behaviour of every other
>>>language I know of.
>>>
>>>printf( "%.2f",0.995)
>>>-> 0.99
>>>
>>>Because libm are carefully written nowdays and other languages
>>>libraries are either built over libm or much more careful than
>>>Smalltalk were (that mostly means more recent).
>>>
>>>> Anyway, we should try not to use floats without a very, very good reason.
>>>> Like we have to send them outside of Smalltalk or we really need the speed
>>>> or decimals and fractions take up too much memory.  But then we must live
>>>> with their inaccuracies and display mess.
>>>>
>>>
>>>Good advice, let's put those expectations on decimal fractions
>>>(ScaledDecimal/FixedPoint) or general Fraction.
>>>
>>>> I have an untested theory that fractions can be close in speed to floats
>>>> because divisions (that are expensive) can be pushed to the end of a
>>>> computation because with fractions they are multiplies.
>>>>
>>>> Lou
>>>
>>>Why not, but huge numerators and denominators are not cheap compared
>>>to Float operations.
>>>OK reducing the fraction is the expensive part, but how does the cost
>>>grow versus the length of operands?
>>>
>>>Also some geometric operations are not even possible on Q (hypot) so
>>>you might soon need AlgebraicNumber.
>>>And Smalltalk is also about graphics and geometry.
>>>
>>>Nicolas
>>>
>>>> -----------------------------------------------------------
>>>> Louis LaBrunda
>>>> Keystone Software Corp.
>>>> SkypeMe callto://PhotonDemon
>>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>>
>>>>
>>>
>> -----------------------------------------------------------
>> Louis LaBrunda
>> Keystone Software Corp.
>> SkypeMe callto://PhotonDemon
>> mailto:[hidden email] http://www.Keystone-Software.com
>>
>>
>
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com


Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Nicolas Cellier
Well, that's what I'm fighting against: looking good.
The good looking float are putting plenty of traps on our path, and it's better to know about it.
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.
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.

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.

Nicolas



2013/3/29 Louis LaBrunda <[hidden email]>
Hi Nicolas,

Sorry to be getting back to this so late.  I take back what I said about
asTrueFraction.  I'm sure it is fine.  But I think I question its use in
this case.

This all started when Stéphane said this:

        0.995 printShowingDecimalPlaces: 2   ==>  '1.00'

was wrong and I didn't think so.

When one uses a method like printShowingDecimalPlaces: one expects (maybe
there is some other similar method that one should expect this) the result
to look good (yes that is very subjective) but I would say looking good is
more important than being accurate.  Yes, that is an admission that
asTrueFraction is the accurate way to convert floats.  Looking good would
mean rounded nicely.

Maybe I'm expecting printShowingDecimalPlaces: to be something it isn't
intended to be but I don't see any other similar method that would perform
the pretty way.

Lou

On Tue, 26 Mar 2013 22:11:41 +0100, Nicolas Cellier
<[hidden email]> wrote:

>2013/3/26 Louis LaBrunda <[hidden email]>:
>> Hi Nicolas,
>>
>> snip...
>>
>>>> In VA Smalltalk:
>>>>
>>>> 0.995 = 0.995s3 => true
>>>> 0.995 < 0.995s3 => false
>>
>>>This is a default st80 behavior which converts minimumGenerality
>>>number to maximumGenerality.
>>
>> In VA when one converts 0.995 to decimal, one gets 0.995s15, which when
>> compared to 0.995s3 is equal.  And when 0.995s3 is converted to float that
>> float compares equal to 0.995.
>>
>>>Maybe some of these conventions are hardwired in VM, I don't know, but
>>>in other dialects it's handled at image side.
>>
>>>The idea was this one: if you perform an operation between an inexact
>>>value and an exact value, the result is inexact.
>>>So Float + * / - Integer,Fraction,ScaledDecimal will result into a Float.
>>>Thus Float got a higher generality.
>>
>> This would imply that one should convert the ScaledDecimal to a Float
>> before the compare.  But as above that would not change things (I think
>> maybe because VA uses 8 byte floats).
>>
>> This is from Squeak:
>>
>> 0.995s3 asFloat
>>  0.995
>>
>> 0.995s3 asFloat = 0.995
>>  true
>>
>> 0.995 asScaledDecimal
>>  0.99499999s8
>>
>> (995 / 1000) asScaledDecimal
>>  0.995s3
>>
>> 0.995 asTrueFraction asScaledDecimal
>>  0.99499999999999999555910790149937383830547332763671875s53
>>
>> (0.995 * 1000000000) asScaledDecimal / 1000000000
>>  0.99500000s8
>>
>
>Yep, but (0.995 * 1000000000) is inexact...
>You can check that (0.995 * 1000000000) ~~ (0.995 asFraction * 1000000000)
>
>You cannot rely on results of any such inexact calculus, or you'll be
>building on sand.
>
>> 0.995 * 1000000000
>>  9.95e8
>>
>> Sorry, but I have run out of time to play at the moment.  So, I will just
>> throw a thought out there.  I think there may be a problem with
>> asTrueFraction.  Which if implemented differently might not make 0.995 <
>> 0.995s3.
>>
>
>Well I doubt, but I'm all ears ;)
>
>(0.995 asFraction storeStringBase: 2)
>-> '(2r11111110101110000101000111101011100001010001111010111/2r100000000000000000000000000000000000000000000000000000)'.
>
>(0.995 successor) asFraction storeStringBase: 2
>-> '(2r11111110101110000101000111101011100001010001111011/2r100000000000000000000000000000000000000000000000000)'
>-> '(2r11111110101110000101000111101011100001010001111011000/2r100000000000000000000000000000000000000000000000000000)'.
>
>(0.995 predecessor) asFraction storeStringBase: 2
>-> '(2r1111111010111000010100011110101110000101000111101011/2r10000000000000000000000000000000000000000000000000000)'
>-> '(2r11111110101110000101000111101011100001010001111010110/2r100000000000000000000000000000000000000000000000000000)'.
>
>0.995 ulp asFraction storeStringBase: 2
>-> '(2r1/2r100000000000000000000000000000000000000000000000000000)'.
>
>(995/1000 - 0.995 asFraction) / 0.995 ulp
>-> 0.04.
>
>(995/1000 - 0.995 successor asFraction) / 0.995 ulp
>->  -0.96.
>
>(995/1000 - 0.995 successor asFraction) / 0.995 ulp
>->  1.04.
>
>and numerator/denominator have this property:
>
>2r11111110101110000101000111101011100001010001111010111 highBit
>-> 53.
>2r100000000000000000000000000000000000000000000000000000 highBit
>-> 54.
>
>So, 53 bits of significand, a power of two on denominator, that sounds
>like a correct Float, slightly smaller than 1.
>Next significand and previous significand are both further of
>(995/1000) than 0.995 is.
>0.995 is closest Float to 995/1000 and is smaller than 995/1000, no doubt.
>
>Nicolas
>
>>>The idea behind Squeak change is that every Float has an exact value
>>>(asTrueFraction).
>>>Since we have only two possible answers true/false for comparison, and
>>>no maybe or dontKnow, it makes sense to compare the exact value.
>>>This reduces the number of paradoxal equalities
>>>
>>>| a b c |
>>>a := 1 << Float precision.
>>>b := a + 1.
>>>c := a asFloat.
>>>{
>>>c = b.
>>>c = a.
>>>a = b.
>>>}
>>>
>>>In VW and VA, the first two are true, the last is false, which
>>>suggests that = is not an equivalence relation.
>>>In Squeak, only the second one is true.
>>>
>>>Same with inequalities, we expect (a < b) & (a = c) ==> (c < b) etc...
>>>This is still true in Squeak, not in VA/VW/st80.
>>>I think gst and Dolphin and maybe stx adopted Squeak behavior (to be confirmed).
>>>
>>>
>>>> I think in VA Smalltalk there is some VM magic going on that makes the
>>>> above work the way it does.  The #= and #< of Float are implemented in a
>>>> primitive.  I guess when converting the '0.995' string to a float a little
>>>> is lost and that would make it less than 0.995s3 but there is a lot of code
>>>> floating around (sorry about the puns) to make floats look better.  In that
>>>> case I would think people would want (0.995 printShowingDecimalPlaces: 2)
>>>> to show '1.00' and not '0.99'.
>>>>
>>>
>>>No, people should not rely on such behavior with Floats, because
>>>sooner than later they will be bitten.
>>>We cannot cheat very long with this kind of assumptions.
>>>My POV is that it is better to educate about false expectations with
>>>Float, and that's the main benefit of (1/10) ~= 0.1.
>>>
>>>I would add that such print policy is not the behaviour of every other
>>>language I know of.
>>>
>>>printf( "%.2f",0.995)
>>>-> 0.99
>>>
>>>Because libm are carefully written nowdays and other languages
>>>libraries are either built over libm or much more careful than
>>>Smalltalk were (that mostly means more recent).
>>>
>>>> Anyway, we should try not to use floats without a very, very good reason.
>>>> Like we have to send them outside of Smalltalk or we really need the speed
>>>> or decimals and fractions take up too much memory.  But then we must live
>>>> with their inaccuracies and display mess.
>>>>
>>>
>>>Good advice, let's put those expectations on decimal fractions
>>>(ScaledDecimal/FixedPoint) or general Fraction.
>>>
>>>> I have an untested theory that fractions can be close in speed to floats
>>>> because divisions (that are expensive) can be pushed to the end of a
>>>> computation because with fractions they are multiplies.
>>>>
>>>> Lou
>>>
>>>Why not, but huge numerators and denominators are not cheap compared
>>>to Float operations.
>>>OK reducing the fraction is the expensive part, but how does the cost
>>>grow versus the length of operands?
>>>
>>>Also some geometric operations are not even possible on Q (hypot) so
>>>you might soon need AlgebraicNumber.
>>>And Smalltalk is also about graphics and geometry.
>>>
>>>Nicolas
>>>
>>>> -----------------------------------------------------------
>>>> Louis LaBrunda
>>>> Keystone Software Corp.
>>>> SkypeMe callto://PhotonDemon
>>>> mailto:[hidden email] http://www.Keystone-Software.com
>>>>
>>>>
>>>
>> -----------------------------------------------------------
>> Louis LaBrunda
>> Keystone Software Corp.
>> SkypeMe callto://PhotonDemon
>> mailto:[hidden email] http://www.Keystone-Software.com
>>
>>
>
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com





Reply | Threaded
Open this post in threaded view
|

Re: The joys (or not) of floating point numbers

Chris Muller-3
It also is good for remembering presentation must be able to be
distinct from internal representation.

On Fri, Mar 29, 2013 at 1:41 PM, Nicolas Cellier
<[hidden email]> wrote:

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