[squeak-dev] [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

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

[squeak-dev] [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Nicolas Cellier-3
Happy new year everyone.
After VWNC recent discussion about comparing Point and Number, I tried
to make a review of my previous work concerning all these minor (but
annoying) comparison bugs.


I think I now have an acceptable and consistent solution.
This is spreaded across several mantis bug reports:

http://bugs.squeak.org/view.php?id=3374
http://bugs.squeak.org/view.php?id=6719
http://bugs.squeak.org/view.php?id=7259
http://bugs.squeak.org/view.php?id=7260

It should also solve:


http://bugs.squeak.org/view.php?id=3360
http://bugs.squeak.org/view.php?id=6601
(I took andrew solution from the last one)

Comments, code critics, flames, etc... are welcome

Nicolas


Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Andreas.Raab
nicolas cellier wrote:
> I think I now have an acceptable and consistent solution.
> This is spreaded across several mantis bug reports:

Wow. This is quite a bit of work. Here are some comments:

> http://bugs.squeak.org/view.php?id=3374

[transitive equality of arithmetic comparison]

I'm a little confused here which version is the "correct" patch. I'm
assuming it's the M3374-xxx versions of the files - if not, please let
me know.

I generally like the solution proposed for comparisons here but the
coercion methods itself look a little odd: First, they appear to rely on
a method #isFinite which is not defined anywhere and second -assuming
that isFinite returns false for well-defined infinities like IEEE 754- I
am not sure why two infinities should not compare equal. I don't have my
IEEE 754 spec handy but at least for Float I think that is well defined.
Can you explain your reasoning here a little more?

I really like the fix for Integer/Fraction/Float hash.

> http://bugs.squeak.org/view.php?id=6719

[NaN comparisons]

This one I don't like quite as much. How about a much simpler version
along the lines of:

Magnitude <= aMagnitude
        "Answer whether the receiver is less than or equal to the argument."

        ^(self > aMagnitude or:[aMagnitude isNaN]) not

Etc. This should work just as well and requires only changes in
Magnitude instead of polluting too many subclasses (may require
promoting isNaN to Magnitude).

Also, out of curiosity, what's your take on the IEEE 754 requirement
that NaN compares not equal to itself? This breaks fundamental
relationships (for example you can't use NaN in Sets or Dicts) and my
feeling has always been that it would be more useful if:
* there was a bit-fiddling test for Float>>isNaN
* NaNs would compare equal to itself (though not necessarily to NaNs
with different bit-patterns)
* Standard float prims would *never* return NaN but rather fail
The last one proved tremendously helpful in Croquet where I've been
using fdlibm and simply fail any float prims that would produce NaNs.
The image can then take care of it properly.

> http://bugs.squeak.org/view.php?id=7259

[point-number comparisons]

This is an elegant solution (nice use of adaptTo:andCompare:) but I'm
not sure how much code will break with it. Have you tried running this
for a while in daily use?

> http://bugs.squeak.org/view.php?id=7260

[float prim behavior with NaN]

I'm with you on this one. The primitives are very, very badly broken at
this point and I'm really surprised this has escaped us for so long.

All in all, this is great stuff!

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Nicolas Cellier-3
Andreas Raab a écrit :

> nicolas cellier wrote:
>> I think I now have an acceptable and consistent solution.
>> This is spreaded across several mantis bug reports:
>
> Wow. This is quite a bit of work. Here are some comments:
>
>> http://bugs.squeak.org/view.php?id=3374
>
> [transitive equality of arithmetic comparison]
>
> I'm a little confused here which version is the "correct" patch. I'm
> assuming it's the M3374-xxx versions of the files - if not, please let
> me know.
>

Yes, the correct version is the one corresponding to last Installer hook
in bugnotes.

> I generally like the solution proposed for comparisons here but the
> coercion methods itself look a little odd: First, they appear to rely on
> a method #isFinite which is not defined anywhere and second -assuming
> that isFinite returns false for well-defined infinities like IEEE 754- I
> am not sure why two infinities should not compare equal. I don't have my
> IEEE 754 spec handy but at least for Float I think that is well defined.
> Can you explain your reasoning here a little more?
>

isFinite is a pre-requisite that can be found at
http://bugs.squeak.org/view.php?id=6983

This is corresponding to Installer hook (Installer mantis ensureFix: 6983)

Definition is very simple and answer false both for nans and infinities
isFinite
     ^self - self = 0.0

Concerning equality of infinities, I think IEEE 754 say they are equal
Once, i did wonder why. My rationale is
        (Float infinity - Float infinity) isNan.
Since the difference of two infinities is not defined, how can we decide
they represent equal quantities ?
I developped this theme at http://bugs.squeak.org/view.php?id=6729

However, I did not change anything, that would mean change IEEE,
hardware implementation, etc... A bit too much.

The only thing I change is this:
        (10 raisedTo: 400) < Float infinity.
It used to be equal, because it's asFloat avatar isInfinite...


> I really like the fix for Integer/Fraction/Float hash.
>

Then thank Andrew Tween for the base idea
http://bugs.squeak.org/view.php?id=6601

>> http://bugs.squeak.org/view.php?id=6719
>
> [NaN comparisons]
>
> This one I don't like quite as much. How about a much simpler version
> along the lines of:
>
> Magnitude <= aMagnitude
>     "Answer whether the receiver is less than or equal to the argument."
>
>     ^(self > aMagnitude or:[aMagnitude isNaN]) not
>
> Etc. This should work just as well and requires only changes in
> Magnitude instead of polluting too many subclasses (may require
> promoting isNaN to Magnitude).
>

Agree, this is much more simple.
I was probably biased by other situations when there is not a total
order like Number and Point comparison.

However there are other cases like these ones where it could serve:

(1/2) < #(0 1 2). "#(false true true)"
(1/2) > #(0 1 2). "Array does not understand <"

(1/2) < '1'. "true"
(1/2) > '1'. "Error: Instances of Fraction are not indexable"

I agree, these are not beautiful examples, some functionalities that
might better take there way out of the image.

Notice that:
3 > '2' and: [3.0 > '2']. "true"

Why not define in Fraction what already is in Integer and Float?

> Also, out of curiosity, what's your take on the IEEE 754 requirement
> that NaN compares not equal to itself? This breaks fundamental
> relationships (for example you can't use NaN in Sets or Dicts) and my

Gasp, I thought I could retrieve an official reference...
successor ISO/IEC 10967-2 is not very verbose about that
http://www.cs.chalmers.se/~kent/ISOStandards/SC22/WG11/LIA-2/N424.ps

But you can read page 8 of Kahan's
http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF
(via http://en.wikipedia.org/wiki/IEEE_754-1985)

Anyway, this is implemented by all libraries I know of:

#include <stdio.h>
int main() {
double nan;
nan =0.0 / 0.0;
printf("nan == nan is %s\n",(nan==nan)?"true":"false");
return 0;
}

Just try the Smalltalk primitive to confirm...
Float nan = Float nan


> feeling has always been that it would be more useful if:
> * there was a bit-fiddling test for Float>>isNaN
> * NaNs would compare equal to itself (though not necessarily to NaNs
> with different bit-patterns)
> * Standard float prims would *never* return NaN but rather fail
> The last one proved tremendously helpful in Croquet where I've been
> using fdlibm and simply fail any float prims that would produce NaNs.
> The image can then take care of it properly.
>

Agree, I much prefer an Exception (a pimitiveFail) to a NaN.
NaN is not of any use in Smalltalk, except for hooking a poor man
external world.

>> http://bugs.squeak.org/view.php?id=7259
>
> [point-number comparisons]
>
> This is an elegant solution (nice use of adaptTo:andCompare:) but I'm
> not sure how much code will break with it. Have you tried running this
> for a while in daily use?
>

No, I have absolutely no guaranty.
My Rationale is as follow:
-1) old behaviour is rather broken
        (1/2) > (1 @3). "MNU"
        2 <= (1@3). "true ???"
        2 >= (1@3). "true ???"
-2) It is easy to revert to a (corrected) coercion behaviour

Point>>adaptToNumber: rcvr andCompare: comparisonSelector
     ^rcvr@rcvr perform: comparisonSelector with: self

However, such coercion would be a typical case where defining
Magnitude >= aMagnitude
        ^(self > aMagnitude or:[aMagnitude isNaN]) not
would not work... (even if Point>>isNan is defined).

>> http://bugs.squeak.org/view.php?id=7260
>
> [float prim behavior with NaN]
>
> I'm with you on this one. The primitives are very, very badly broken at
> this point and I'm really surprised this has escaped us for so long.
>
> All in all, this is great stuff!
>

Thanks

> Cheers,
>   - Andreas
>
>


Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Andreas.Raab
nicolas cellier wrote:
> Yes, the correct version is the one corresponding to last Installer hook
> in bugnotes.

Ah, yes, sorry I missed that. It's too sprinkled around in the notes ;-)

> isFinite is a pre-requisite that can be found at
> http://bugs.squeak.org/view.php?id=6983
>
> This is corresponding to Installer hook (Installer mantis ensureFix: 6983)
>
> Definition is very simple and answer false both for nans and infinities
> isFinite
>     ^self - self = 0.0
>
> Concerning equality of infinities, I think IEEE 754 say they are equal
> Once, i did wonder why. My rationale is
>     (Float infinity - Float infinity) isNan.
> Since the difference of two infinities is not defined, how can we decide
> they represent equal quantities ?

Interesting point. However, I do think that a = a should be true for all
objects including  Infinity and NaN.

>> I really like the fix for Integer/Fraction/Float hash.
>>
>
> Then thank Andrew Tween for the base idea
> http://bugs.squeak.org/view.php?id=6601

Ah, interesting. I had totally missed that.

>>> http://bugs.squeak.org/view.php?id=6719
>>
>> [NaN comparisons]
[... snip ...]

> However there are other cases like these ones where it could serve:
>
> (1/2) < #(0 1 2). "#(false true true)"
> (1/2) > #(0 1 2). "Array does not understand <"
>
> (1/2) < '1'. "true"
> (1/2) > '1'. "Error: Instances of Fraction are not indexable"
>
> I agree, these are not beautiful examples, some functionalities that
> might better take there way out of the image.
>
> Notice that:
> 3 > '2' and: [3.0 > '2']. "true"
>
> Why not define in Fraction what already is in Integer and Float?

No reason. I wasn't aware that your changes addressed both situations. I
was only concerned that addressing the NaN issues would lead to a
proliferation of Magnitude subclasses having to implement all of the
comparison operations instead of just a limited subset.

>> Also, out of curiosity, what's your take on the IEEE 754 requirement
>> that NaN compares not equal to itself? This breaks fundamental
>> relationships (for example you can't use NaN in Sets or Dicts) and my
>
> Gasp, I thought I could retrieve an official reference...
> successor ISO/IEC 10967-2 is not very verbose about that
> http://www.cs.chalmers.se/~kent/ISOStandards/SC22/WG11/LIA-2/N424.ps
>
> But you can read page 8 of Kahan's
> http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF
> (via http://en.wikipedia.org/wiki/IEEE_754-1985)
>
> Anyway, this is implemented by all libraries I know of:

One idle thought I had today was whether one couldn't entirely get rid
of float-valued NaNs and instead introduce a well-known NaN instance
that *isn't* an instance of Float and consequently also isn't a Number,
doesn't do any arithmetic etc. etc. etc.

It would be fairly simple to change the VM to have a well-known NaN slot
in the specialObjectsArray so that when a primitive attempts to return a
float-valued NaN via pushFloat: the VM instead pushes that NaN object.
This would fix 99% of all places that could ever return a float-valued
NaN, including things like ByteArray>>doubleAt:, or the FFI etc.

What I have personally no clue about is whether anyone ever uses
float-valued NaNs for anything useful. I have never done that but there
may be people who have and it would be interesting to see whether they
have any insight into the use of a non-float NaN instance.

>>> http://bugs.squeak.org/view.php?id=7259
>>
>> [point-number comparisons]
>>
>> This is an elegant solution (nice use of adaptTo:andCompare:) but I'm
>> not sure how much code will break with it. Have you tried running this
>> for a while in daily use?
>>
>
> No, I have absolutely no guaranty.

Sure. I'm just asking for anecdotal evidence in your day-to-day images.
Are you actively using these changes?

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Eliot Miranda-2


On Tue, Jan 6, 2009 at 8:49 PM, Andreas Raab <[hidden email]> wrote:
nicolas cellier wrote:
Yes, the correct version is the one corresponding to last Installer hook in bugnotes.

Ah, yes, sorry I missed that. It's too sprinkled around in the notes ;-)


isFinite is a pre-requisite that can be found at http://bugs.squeak.org/view.php?id=6983

This is corresponding to Installer hook (Installer mantis ensureFix: 6983)

Definition is very simple and answer false both for nans and infinities
isFinite
   ^self - self = 0.0

Concerning equality of infinities, I think IEEE 754 say they are equal
Once, i did wonder why. My rationale is
   (Float infinity - Float infinity) isNan.
Since the difference of two infinities is not defined, how can we decide they represent equal quantities ?

Interesting point. However, I do think that a = a should be true for all objects including  Infinity and NaN.

I used to think the same (at least for infinity & infinitessimal) but no longer..  1 / 0 ~= (Float maxVal * 2).  At first the IEEE rules may seem counter-intuitive but they have been well thoguht-out.  They provide safety for computations that go out of range.  Correctness (in this case lack of false positives) is much more important than "naturalness".



I really like the fix for Integer/Fraction/Float hash.


Then thank Andrew Tween for the base idea http://bugs.squeak.org/view.php?id=6601

Ah, interesting. I had totally missed that. [... snip ...]

However there are other cases like these ones where it could serve:

(1/2) < #(0 1 2). "#(false true true)"
(1/2) > #(0 1 2). "Array does not understand <"

(1/2) < '1'. "true"
(1/2) > '1'. "Error: Instances of Fraction are not indexable"

I agree, these are not beautiful examples, some functionalities that might better take there way out of the image.

Notice that:
3 > '2' and: [3.0 > '2']. "true"

Why not define in Fraction what already is in Integer and Float?

No reason. I wasn't aware that your changes addressed both situations. I was only concerned that addressing the NaN issues would lead to a proliferation of Magnitude subclasses having to implement all of the comparison operations instead of just a limited subset.


Also, out of curiosity, what's your take on the IEEE 754 requirement that NaN compares not equal to itself? This breaks fundamental relationships (for example you can't use NaN in Sets or Dicts) and my

Gasp, I thought I could retrieve an official reference...
successor ISO/IEC 10967-2 is not very verbose about that http://www.cs.chalmers.se/~kent/ISOStandards/SC22/WG11/LIA-2/N424.ps

But you can read page 8 of Kahan's http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF
(via http://en.wikipedia.org/wiki/IEEE_754-1985)

Anyway, this is implemented by all libraries I know of:

One idle thought I had today was whether one couldn't entirely get rid of float-valued NaNs and instead introduce a well-known NaN instance that *isn't* an instance of Float and consequently also isn't a Number, doesn't do any arithmetic etc. etc. etc.

It would be fairly simple to change the VM to have a well-known NaN slot in the specialObjectsArray so that when a primitive attempts to return a float-valued NaN via pushFloat: the VM instead pushes that NaN object. This would fix 99% of all places that could ever return a float-valued NaN, including things like ByteArray>>doubleAt:, or the FFI etc.

What I have personally no clue about is whether anyone ever uses float-valued NaNs for anything useful. I have never done that but there may be people who have and it would be interesting to see whether they have any insight into the use of a non-float NaN instance.


The experience with VisualWorks where we changed over to IEEE (with Inf & NaN) was rthat those people who really cared avbout float arithmetic and knew what they were talking about really wanted IEEE behaviour and did not at all want abstract Infinity Infinitessimal or NaN.  One thing they wanted was easy interoperability (e.g. with high-performance libraries), which means sticking to IEEE.  Introducing abstract Infinity/Infinitessimal/NaN complicates the glue and slows it down.




http://bugs.squeak.org/view.php?id=7259

[point-number comparisons]

This is an elegant solution (nice use of adaptTo:andCompare:) but I'm not sure how much code will break with it. Have you tried running this for a while in daily use?


No, I have absolutely no guaranty.

Sure. I'm just asking for anecdotal evidence in your day-to-day images. Are you actively using these changes?

Cheers,
 - Andreas




Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Andreas.Raab
Eliot Miranda wrote:
> I used to think the same (at least for infinity & infinitessimal) but no
> longer..  1 / 0 ~= (Float maxVal * 2).  At first the IEEE rules may seem
> counter-intuitive but they have been well thoguht-out.  They provide
> safety for computations that go out of range.  Correctness (in this case
> lack of false positives) is much more important than "naturalness".

I agree. But correctness can also mean that neither 1 / 0 nor Float
maxVal * 2 should be allowed to successfully execute primitively.

> The experience with VisualWorks where we changed over to IEEE (with Inf
> & NaN) was rthat those people who really cared avbout float arithmetic
> and knew what they were talking about really wanted IEEE behaviour and
> did not at all want abstract Infinity Infinitessimal or NaN.  One thing
> they wanted was easy interoperability (e.g. with high-performance
> libraries), which means sticking to IEEE.  Introducing abstract
> Infinity/Infinitessimal/NaN complicates the glue and slows it down.

Interesting data point. I'm really torn in this area - it seems like
such a broken behavior to have a ~= a.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

johnmci

On 6-Jan-09, at 10:33 PM, Andreas Raab wrote:

> Eliot Miranda wrote:
>> I used to think the same (at least for infinity & infinitessimal)  
>> but no longer..  1 / 0 ~= (Float maxVal * 2).  At first the IEEE  
>> rules may seem counter-intuitive but they have been well thoguht-
>> out.  They provide safety for computations that go out of range.  
>> Correctness (in this case lack of false positives) is much more  
>> important than "naturalness".
>
> I agree. But correctness can also mean that neither 1 / 0 nor Float  
> maxVal * 2 should be allowed to successfully execute primitively.
>
>> The experience with VisualWorks where we changed over to IEEE (with  
>> Inf & NaN) was rthat those people who really cared avbout float  
>> arithmetic and knew what they were talking about really wanted IEEE  
>> behaviour and did not at all want abstract Infinity Infinitessimal  
>> or NaN.  One thing they wanted was easy interoperability (e.g. with  
>> high-performance libraries), which means sticking to IEEE.  
>> Introducing abstract Infinity/Infinitessimal/NaN complicates the  
>> glue and slows it down.
>
> Interesting data point. I'm really torn in this area - it seems like  
> such a broken behavior to have a ~= a.
>
> Cheers,
>  - Andreas
>

Also read/see http://en.wikipedia.org/wiki/NaN

However the other place where I've been burned with this is doing what  
you think is IEEE math in smalltalk
then converting some of the code to SQL stored procedures and the  
database engine DOES do proper IEEE
logic.

You then discover NaN data being poured into the database via some  
other forms of data collection results
in the stored procedure code giving you different results from the  
original smalltalk code, but only in production
late one dark winter night...


--
=
=
=
========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
=
=
=
========================================================================




Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Paolo Bonzini-2
In reply to this post by Andreas.Raab

> One idle thought I had today was whether one couldn't entirely get rid
> of float-valued NaNs and instead introduce a well-known NaN instance
> that *isn't* an instance of Float and consequently also isn't a Number,
> doesn't do any arithmetic etc. etc. etc.

Another possibility is to have the primitives fail and the fallback code
signal a Notification.  The notification would by default return a NaN
float.  It might be okay to use a NaN object too;; however it should
behave the same way as IEEE NaNs and would have to be interoperable with
FFI and FloatArrays (does Squeak have them?).

I don't think it makes sense to use Integer or Fraction NaNs.  In that
case you do not have infinities either, and raising hard errors makes
more sense.  Note that GNU Smalltalk does not even raise a ZeroDivide
for floating-point division:

  st> 1 / 0
  Object: 1 error: The program attempted to divide a number by zero
  ZeroDivide(Exception)>>signal (AnsiExcept.st:216)
  SmallInteger(Number)>>zeroDivide (AnsiExcept.st:1534)
  SmallInteger>>/ (SmallInt.st:277)
  UndefinedObject>>executeStatements (a String:1)
  nil

  st> 1.0 / 0.0
  Inf

> What I have personally no clue about is whether anyone ever uses
> float-valued NaNs for anything useful.

It allows delaying error checking to after the end of the computation.
Some errors that do not affect the result would be silently ignored;
most errors would result in a NaN.  Of course Smalltalk floats are so
slow that this might not even make a difference (unless you use FFI to
interface with external libraries).

With floating-point, I decided that the best course of action is "assume
the IEEE-754 people are always right" (and that means W. Kahan mostly).

Paolo

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Nicolas Cellier-3
Paolo Bonzini a écrit :

>> What I have personally no clue about is whether anyone ever uses
>> float-valued NaNs for anything useful.
>
> It allows delaying error checking to after the end of the computation.
> Some errors that do not affect the result would be silently ignored;
> most errors would result in a NaN.  Of course Smalltalk floats are so
> slow that this might not even make a difference (unless you use FFI to
> interface with external libraries).
>
> With floating-point, I decided that the best course of action is "assume
> the IEEE-754 people are always right" (and that means W. Kahan mostly).
>
> Paolo
>
>

This is a wise decision for most current situations.

What is unwise is to not fully support IEEE 754 Exception handling.

Default IEE754 rules are not mathematically well founded
They are just pragmatic hacks for solving nicely and efficiently some
common problems.

If we have have different requirements we should be able to trap FPU
exception and provide our own exception handling. And this should occur
from within the image if we pretend Smalltalk is a general purpose language.

What I would like is better IEEE 754 integration and portability.
1) portable way to declare and handle extended double (long double in C)
2) portable way to get/set FPU sticky error flags
3) portable way to activate and catch FPU exceptions
4) portable way to select rounding mode

Alas, that's one point where IEEE 754 success was incomplete...
When reading ieee man pages, it seems there are as many interfaces as OS
versions...
I don't even know which hardware supports or not these traps...
I even wonder if such features were mandatory...
That should not stop us: as suggested, Smalltalk is already sufficiently
slow to afford a sticky flag test at each Float primitive in case no
hardware trap is available.

With a portable C library, we could afford a few more primitives and
decide at image level how to handle these Exceptions (either a
primitiveFail or a quiet NaN in case of INVALID operation for example).

I understand this is not a Smalltalk priority; ST is not known as a
flying Float cruncher...
However, ST markets should better not be restricted by the kernel...

Nicolas


PS: sure, I know gst is among best behaved (with STX) having extended
double...


Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Nicolas Cellier-3
In reply to this post by Andreas.Raab
Andreas Raab a écrit :

> nicolas cellier wrote:
>>>> http://bugs.squeak.org/view.php?id=6719
>>>
>>> [NaN comparisons]
> [... snip ...]
>> However there are other cases like these ones where it could serve:
>>
>> (1/2) < #(0 1 2). "#(false true true)"
>> (1/2) > #(0 1 2). "Array does not understand <"
>>
>> (1/2) < '1'. "true"
>> (1/2) > '1'. "Error: Instances of Fraction are not indexable"
>>
>> I agree, these are not beautiful examples, some functionalities that
>> might better take there way out of the image.
>>
>> Notice that:
>> 3 > '2' and: [3.0 > '2']. "true"
>>
>> Why not define in Fraction what already is in Integer and Float?
>
> No reason. I wasn't aware that your changes addressed both situations. I
> was only concerned that addressing the NaN issues would lead to a
> proliferation of Magnitude subclasses having to implement all of the
> comparison operations instead of just a limited subset.
>

I redefine only one message in Magnitude
 >= aMagnitude
        ^aMagnitude <= self

instead of:
 >= aMagnitude
        ^(self < aMagnitude) not

This is absolutely not necessary and can be skipped.

What I had in mind was that it would be sufficient to define only < in
subclass in case of total order, and only < and <= in case of partial order.
That would work with Nan, but that's not true with Array for example...
Argument class also has to agree on the reverse relation.

> One idle thought I had today was whether one couldn't entirely get rid
> of float-valued NaNs and instead introduce a well-known NaN instance
> that *isn't* an instance of Float and consequently also isn't a Number,
> doesn't do any arithmetic etc. etc. etc.
>
> It would be fairly simple to change the VM to have a well-known NaN slot
> in the specialObjectsArray so that when a primitive attempts to return a
> float-valued NaN via pushFloat: the VM instead pushes that NaN object.
> This would fix 99% of all places that could ever return a float-valued
> NaN, including things like ByteArray>>doubleAt:, or the FFI etc.
>
> What I have personally no clue about is whether anyone ever uses
> float-valued NaNs for anything useful. I have never done that but there
> may be people who have and it would be interesting to see whether they
> have any insight into the use of a non-float NaN instance.
>

Mostly agree but:
1) I would prefer a behaviour controlled at image level
    Read more in my response to Paolo.
2) We cannot just ignore outside world.
    I think Eliot, Paolo, John did answer enough about it.


>>>> http://bugs.squeak.org/view.php?id=7259
>>>
>>> [point-number comparisons]
>>>
>>> This is an elegant solution (nice use of adaptTo:andCompare:) but I'm
>>> not sure how much code will break with it. Have you tried running
>>> this for a while in daily use?
>>>
>>
>> No, I have absolutely no guaranty.
>
> Sure. I'm just asking for anecdotal evidence in your day-to-day images.
> Are you actively using these changes?
>

No, it is in my personal images, but
1) I don't use squeak intensively (not professionally).
2) The changes are far too young.
Some volunteers have to help...

> Cheers,
>   - Andreas
>
>


Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Bryce Kampjes
In reply to this post by Nicolas Cellier-3
nicolas cellier writes:
 > I don't even know which hardware supports or not these traps...
 > I even wonder if such features were mandatory...
 > That should not stop us: as suggested, Smalltalk is already sufficiently
 > slow to afford a sticky flag test at each Float primitive in case no
 > hardware trap is available.

Hopefully Smalltalk will not always be that slow.

All we'd need to do was remove the boxing and unboxing around
floating point operations. Inside single statements, that is
equivalent to the Boolean optimisations that Exupery already
does. Across statements will require a proper optimiser.

Bryce

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Paolo Bonzini-2
[hidden email] wrote:

> nicolas cellier writes:
>  > I don't even know which hardware supports or not these traps...
>  > I even wonder if such features were mandatory...
>  > That should not stop us: as suggested, Smalltalk is already sufficiently
>  > slow to afford a sticky flag test at each Float primitive in case no
>  > hardware trap is available.
>
> Hopefully Smalltalk will not always be that slow.
>
> All we'd need to do was remove the boxing and unboxing around
> floating point operations. Inside single statements, that is
> equivalent to the Boolean optimisations that Exupery already
> does. Across statements will require a proper optimiser.

Good support for matrix/vector operations, possibly with an interface to
BLAS, seems like a much better plan.

Paolo

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Nicolas Cellier-3
In reply to this post by Bryce Kampjes
 <bryce <at> kampjes.demon.co.uk> writes:

>
> nicolas cellier writes:
>  > I don't even know which hardware supports or not these traps...
>  > I even wonder if such features were mandatory...
>  > That should not stop us: as suggested, Smalltalk is already sufficiently
>  > slow to afford a sticky flag test at each Float primitive in case no
>  > hardware trap is available.
>
> Hopefully Smalltalk will not always be that slow.
>
> All we'd need to do was remove the boxing and unboxing around
> floating point operations. Inside single statements, that is
> equivalent to the Boolean optimisations that Exupery already
> does. Across statements will require a proper optimiser.
>
> Bryce
>
>

Great, but if FPU registers are using extra precision (extended double),
then the result of operations might depend on register/memory exchange.

Let's compute (a*b*c) where a,b,c are double precision (Float in squeak).
Let selectors:
- d2e mean (convert double to extended)
- e2d mean (convert extended to double)

For a double d, (d d2e e2d = d) is always true
For an extended e, (e e2d d2e = e) might be false because some bits are lost.

Unoptimized Smalltalk does:
((a d2e * b d2e) e2d d2e * c d2e) e2d.
which should - thanks to IEEE 754 - be strictly equivalent to:
(a * b) * c.

But optimized Smalltalk might evaluate:
((a d2e * b d2e) * c d2e) e2d.
Which is no more equivalent in case (a*b) is inexact...
Of course, result will be more accurate.
But impossible to have bit-identical results depending on optimization level...

Do you plan forcing e2d conversions in generated code?
If not, you will trade bit-identical property for speed
(as most i86 C compilers already do).
Smalltalk vm will fail being hardware independent...
(I suspect this is already the case for libm sin, log etc...)

IMO user should keep control over precision, and not let uncontrolled tools take
fancy decisions.
The right way if we eventually want to profit from this extra precision is to
introduce an ExtendedDouble class (like gst did).

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Tim Olson-4

On Jan 8, 2009, at 2:19 AM, Nicolas Cellier wrote:

> Let's compute (a*b*c) where a,b,c are double precision (Float in
> squeak).
> Let selectors:
> - d2e mean (convert double to extended)
> - e2d mean (convert extended to double)
>
> For a double d, (d d2e e2d = d) is always true
> For an extended e, (e e2d d2e = e) might be false because some bits
> are lost.
>
> Unoptimized Smalltalk does:
> ((a d2e * b d2e) e2d d2e * c d2e) e2d.
> which should - thanks to IEEE 754 - be strictly equivalent to:
> (a * b) * c.

Unfortunately, this is not necessarily so, because of the extra
rounding steps involved:

(a * b) performs a double-precision rounding step after the multiply,
while ((a d2e * b d2e) e2d) performs an extended-precision rounding
step after the multiply, then another double-precision rounding step in
the conversion back to double-precision.  This will result in a
difference in the final values in many cases.

There is a mode bit in x86 to cause the intermediate rounding to be
done with double-precision instead of extended-precision, but that does
not limit the exponent range to the double-precision range, so denormal
results may still be different.

        -- Tim Olson


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Hans-Martin Mosner
Tim Olson schrieb:

>
>
> (a * b) performs a double-precision rounding step after the multiply,
> while ((a d2e * b d2e) e2d) performs an extended-precision rounding
> step after the multiply, then another double-precision rounding step
> in the conversion back to double-precision.  This will result in a
> difference in the final values in many cases.
>
> There is a mode bit in x86 to cause the intermediate rounding to be
> done with double-precision instead of extended-precision, but that
> does not limit the exponent range to the double-precision range, so
> denormal results may still be different.
AFAIK, the Croquet project needs to have exactly reproducible float
arithmetics on all platforms. Would these rounding effects on the x86
affect that goal (perhaps with denormal intermediate results)?
Maybe it would be nice to write a unit test which would uncover
different rounding behaviors between purely-double-precision FP hardware
and extended-precision hardware.

Cheers,
Hans-Martin

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Paolo Bonzini-2

> AFAIK, the Croquet project needs to have exactly reproducible float
> arithmetics on all platforms. Would these rounding effects on the x86
> affect that goal (perhaps with denormal intermediate results)?
> Maybe it would be nice to write a unit test which would uncover
> different rounding behaviors between purely-double-precision FP hardware
> and extended-precision hardware.

http://gcc.gnu.org/PR323

Paolo

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Bryce Kampjes
In reply to this post by Nicolas Cellier-3
Nicolas Cellier writes:
 >  <bryce <at> kampjes.demon.co.uk> writes:
 >
 > >
 > > nicolas cellier writes:
 > >  > I don't even know which hardware supports or not these traps...
 > >  > I even wonder if such features were mandatory...
 > >  > That should not stop us: as suggested, Smalltalk is already sufficiently
 > >  > slow to afford a sticky flag test at each Float primitive in case no
 > >  > hardware trap is available.
 > >
 > > Hopefully Smalltalk will not always be that slow.
 > >
 > > All we'd need to do was remove the boxing and unboxing around
 > > floating point operations. Inside single statements, that is
 > > equivalent to the Boolean optimisations that Exupery already
 > > does. Across statements will require a proper optimiser.
 > >
 > > Bryce
 > >
 > >
 >
 > Great, but if FPU registers are using extra precision (extended double),
 > then the result of operations might depend on register/memory exchange.
 >

The x86 SSE2 instruction set uses 64 bit floats. It also supports
16 floating point registers on 64 bit platforms. My plan is to use
that.

IMO the user needs control over the precision/portability/performance
tradeoffs but I haven't thought of any good ways of providing such
control.

Bryce

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Tim Olson-4
In reply to this post by Hans-Martin Mosner

On Jan 8, 2009, at 9:30 AM, Hans-Martin Mosner wrote:

> AFAIK, the Croquet project needs to have exactly reproducible float
> arithmetics on all platforms. Would these rounding effects on the x86
> affect that goal (perhaps with denormal intermediate results)?

Yes.

> Maybe it would be nice to write a unit test which would uncover
> different rounding behaviors between purely-double-precision FP
> hardware
> and extended-precision hardware.

I'd have to play around a bit to get this into a Squeak unit test, but
here's a test vector which shows the effect:

        3ff3208a25e04e87 * 000316dd1d02d1ae

        x86 result: 0003b16ef930a76e
        powerPC result: 0003b16ef930a76f

These are IEEE double-precision floating-point numbers, specified in
hex (big-endian) so that they are bit exact (no conversion error from a
decimal representation).  The first number is between 1.0 and 2.0,
while the second number is a denormal value.  The product shows an lsb
difference between an x86 platform (extended-precision FPU) and a PPC
platform (double-precision FPU), even when the x86 floating-point
control word is set to use double-precision rounding for all results.

        -- Tim Olson


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Hans-Martin Mosner
Tim Olson schrieb:
>
> I'd have to play around a bit to get this into a Squeak unit test, but
> here's a test vector which shows the effect:
Thanks for that; I've made it into a unit test (see attachment) but at
the moment I'm unsure about the course of action that we should take.

First of all, does it matter? If I understand correctly, this behavior
is only present for denormalized numbers. Do these appear in real-world
cases? My guess is that an appropriate computation using numbers with
minimum exponent is the only way of getting denormalized numbers in
real-world programs. I'd guess that for example, with repeated
applications of 3D transformation matrixes which would combine to an
identity transormation if their numbers had infinite precision, you
could get into such a situation. Imagine repeated rotations by 10
degrees - after 36 steps you would theoretically have identity, but your
actual transformation will be slightly off. This would be a typical
Croquet case, and therefore I think that the probability of
miscalculation is real.

I've tried to analyze the case in question and came to the following
results:
The exact mantissa after multiplication is 3B16EF930A76E.80002C69F96C2
(the hex digits after the point are those that should be rounded off
when going to a 52-bit mantissa). The result with "A76F" as the last hex
digits would therefore be the correct value for an IEEE-754 double
precision multiplication (rounding to the nearest representable number),
so the PPC implementation does it right.
When doing an extended double precision multiplication, there are some
more bits in the mantissa, and the mantissa of the intermediate result
looks like ...A76E.800 which is exacly in the middle between two
representable numbers. Converting to double precision involves rounding
the mantissa again, and the rounding rule for this case (exact middle)
says to round to the nearest even number, which is ...A76E.

Is it at all possible to get the x86 FPU to produce the correct result
for this situation?
Interestingly, this article
(http://www.vinc17.org/research/extended.en.html) claims that the FPU is
set up for incorrect rounding under Linux only, but I could not
reproduce the test case given there with Squeak (which probably means
that I mistranslated the Java example).
I have not yet tried the unit test under Windows to check whether the
rounding mode is really set differently there.
If the test runs successfully under Windows, there might be a chance of
setting the rounding mode of the FPU for correct double precision
rounding under Linux, too.

Cheers,
Hans-Martin

'From Squeak3.10.2 of ''5 June 2008'' [latest update: #7179] on 9 January 2009 at 8:28:06 am'!

!FloatTest methodsFor: 'IEEE 754' stamp: 'hmm 1/9/2009 08:18'!
testDenormalResultWithExtendedPrecision
        "The x86 FP hardware uses 80-bit internal representation.
        Example supplied by Tim Olson on the squeak-dev mailing list:
                3ff3208a25e04e87 * 000316dd1d02d1ae

                x86 result:        0003b16ef930a76e
                powerPC result:    0003b16ef930a76f

                These are IEEE double-precision floating-point numbers, specified in hex (big-endian)
                so that they are bit exact (no conversion error from a decimal representation).
                The first number is between 1.0 and 2.0, while the second number is a denormal value.
                The product shows an lsb difference between an x86 platform (extended-precision FPU)
                and a PPC platform (double-precision FPU), even when the x86 floating-point
                control word is set to use double-precision rounding for all results."

        | f1 f2 product |
        f1 := 0.0+0.0.
        f2 := 0.0+0.0.
        f1 basicAt: 1 put: 16r3FF3208A; basicAt: 2 put: 16r25E04E87.
        f2 basicAt: 1 put: 16r000316DD; basicAt: 2 put: 16r1D02D1AE.
        product := f1 * f2.
        self assert: (product basicAt: 1) = 16r0003B16E.
        self assert: (product basicAt: 2) = 16rF930A76F! !


Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: [ANN] Number comparison, hash, NaN, Point, and other partially ordered sets

Paolo Bonzini-2

> Is it at all possible to get the x86 FPU to produce the correct result
> for this situation?

You can also try compiling the Squeak VM with -mfpmath=sse.

Paolo

12