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:
[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
[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.
[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).
[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