# Fraction equality and Float infinity problem Classic List Threaded 16 messages Open this post in threaded view
|

## Fraction equality and Float infinity problem

 Large Fraction asFloat do overflow and answer Float infinity.   ((11 raisedTo: 400) / 2) asFloat = Float infinity. "is true" So far, nothing wrong, except i prefer exception, but that was another discussion. But then they also equal Float infinity, and that sound strange to me:     ((11 raisedTo: 400) / 2) = Float inifinity. "is true" What is bad in this behavior ? It is that you don't have equality transitivity property any more, and that is a flaw:     ((11 raisedTo: 400) / 2) = Float inifinity. "is true"     ((13 raisedTo: 400) / 2) = Float inifinity. "is true"     ((11 raisedTo: 400) / 2) = ((13 raisedTo: 400) / 2). "is false" Then you can expect very weird bugs again in Sets. Add these 3 objects to a Set. Since transitivity is broken, the size of the set will vary according to the order you will add objects to it, the hash code algorithm and the set capacity. Something very nasty. Sure, few people use Large Fractions, and knowing this, they'd rather not, but this is not the right argument. Also, the hash correction i'am proposing is likely to make things worse. So we have to fix this one. Any idea but testing for infinity in adaptToFraction:andSend: / adaptToFloat:andSend: ? This is another reason why i really prefer arithmetic exceptions: handle such case. But i cannot move to arithmetic exception alone.
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 Wow. Great catch. Clearly, this is broken. I think we need to change this coercion to something that deals with the issue properly (e.g., responding false to the comparison in question). Any ideas how to fix that? Cheers,    - Andreas nicolas cellier wrote: > Large Fraction asFloat do overflow and answer Float infinity. >   ((11 raisedTo: 400) / 2) asFloat = Float infinity. "is true" > So far, nothing wrong, except i prefer exception, but that was another > discussion. > > But then they also equal Float infinity, and that sound strange to me: >     ((11 raisedTo: 400) / 2) = Float inifinity. "is true" > > What is bad in this behavior ? It is that you don't have equality transitivity > property any more, and that is a flaw: >     ((11 raisedTo: 400) / 2) = Float inifinity. "is true" >     ((13 raisedTo: 400) / 2) = Float inifinity. "is true" >     ((11 raisedTo: 400) / 2) = ((13 raisedTo: 400) / 2). "is false" > > Then you can expect very weird bugs again in Sets. Add these 3 objects to a > Set. Since transitivity is broken, the size of the set will vary according to > the order you will add objects to it, the hash code algorithm and the set > capacity. Something very nasty. > > Sure, few people use Large Fractions, and knowing this, they'd rather not, but > this is not the right argument. > > Also, the hash correction i'am proposing is likely to make things worse. > So we have to fix this one. Any idea but testing for infinity in > adaptToFraction:andSend: / adaptToFloat:andSend: ? > > This is another reason why i really prefer arithmetic exceptions: handle such > case. But i cannot move to arithmetic exception alone. > > >
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

In reply to this post by Nicolas Cellier-3

Well, the problem is not only for infinity (Overflow).

It is also true for underflow.
(2/(11 raisedTo: 400)) = 0.0. "is true"
(2/(11 raisedTo: 400)) = 0. "is false"

And in fact, the equality transitivity problem can show up for any fraction not exactly representable in IEEE Floating point, that is most Fractions.

Since Fraction set is dense in set of real numbers, i can find an infinite number of Fractions lying between two Float. Since IEEE floating point arithmetic only have a finite number of possible values, then for each floating point value, there exist an infinite number of fractions that will be equal to this float (in current implementation, not mathematically), but the fraction will not equal to each other, thanks to exact arithmetic.

Example:
| a b |
a := (16rFFFFFFFFFFFFF11 / 16r1000000000000000).
b := (16rFFFFFFFFFFFFF10 / 16r100000000 0000000).
c := a asFloat.
{a = b.
a = c.
b = c.}. "is {false . true . true}"

Knowing this, i'am not sure that ((1/3) asFloat = (1/3)) should answer true. Maybe that should be only the case for exact representation like 1/2 1/4 3/4 etc...

But in this case, we also have to redefine coercion to coercing to Fraction instead of Float, because Fraction are more general (yes, Float is a subset of Fraction).

If we do not coerce to exact arithmetic, we will have ((1/3) asFloat - (1/3)) isZero, and still we might be caught by some form of equality problem...

Thus are we ready to exchange our fast floating point algorithm for slower Fraction, with a huge number of useless digits, each time somebody introduce a Fraction.
Are we really sure we vote for this perfect system ?
I am not sure at all.

And that is also the case between floating points and integers.
Sur e other dialects also have the equality problem, maybe not for Infinity, but for less trivial inexact arithmetic case.

All is coming from problem of these languages calling floating point numbers real. Real is more general than fraction, ah yes, we have been foolished by this one.

What should we do ? iFRANCE exprimez-vous !

Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 In reply to this post by Andreas.Raab Hi Andreas, I agree we should answer false to equality test, unless exact arithmetic. Note that (1/3) asFloat asFraction = (1/3) answer false since asTrueFraction is used, but (1/2) asFloat asFraction = (1/2) is true, and that is exactly how we like it. I think we should change coercion algorithm for equality test relying on the asTrueFraction, but not touch + * - / since it would break lot of code. This could be something like: Float>>adaptToFraction: rcvr andSend: selector     ^selector = #=         ifTrue: [[rcvr = self asTrueFraction]             "have to handle NaN and Infinity"             on: Error do: [:exc | exc return: false]]         ifFalse: [rcvr asFloat perform: selector with: self]. same in Fraction>>adpatToFloat: rcvr andSend: selector This does also apply to < > <= >= ~= (some are inherited and need not being handled, some must be handled the same way as =, except error handling block because we cannot compare to NaN and should raise an error...). So we have to complexify above method a bit. If it becomes too complex, we'll have to use more specialized selectors. Note that same stuff is to be done for Float/Integer coercion:   | a b c |   a := 16rFFFFFFFFFFFFF81.   b := 16rFFFFFFFFFFFFF82.   c := a asFloat.   {a = b.    a = c.    b = c.} Maybe we can also expect advices from other Smalltalkers, and make various dialect response more uniform on such a Kernel subject. I went on vwnc mailing list with these, but no answer yet. Agree ? Nicolas Le Mardi 28 Mars 2006 12:45, Andreas Raab a écrit : > Wow. Great catch. Clearly, this is broken. I think we need to change > this coercion to something that deals with the issue properly (e.g., > responding false to the comparison in question). Any ideas how to fix that? > > Cheers, >    - Andreas >
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 Nicolas Thanks for all these emails. Keep going :) For the compatibility between dialects we should not dream (else we   would not have new calling initialize which is extremely cool as a   teacher and programmer too). My feeling is that if we can improve squeak + document the problem   with tests + evaluate how we can move without breaking too much existing code then we win :) Stef > Hi Andreas, > > I agree we should answer false to equality test, unless exact   > arithmetic. > Note that (1/3) asFloat asFraction = (1/3) answer false since   > asTrueFraction > is used, > but (1/2) asFloat asFraction = (1/2) is true, and that is exactly   > how we like > it. > > I think we should change coercion algorithm for equality test   > relying on the > asTrueFraction, but not touch + * - / since it would break lot of   > code. > This could be something like: > > Float>>adaptToFraction: rcvr andSend: selector >     ^selector = #= >         ifTrue: [[rcvr = self asTrueFraction] >             "have to handle NaN and Infinity" >             on: Error do: [:exc | exc return: false]] >         ifFalse: [rcvr asFloat perform: selector with: self]. > > same in Fraction>>adpatToFloat: rcvr andSend: selector > > This does also apply to < > <= >= ~= (some are inherited and need   > not being > handled, some must be handled the same way as =, except error   > handling block > because we cannot compare to NaN and should raise an error...). > So we have to complexify above method a bit. If it becomes too   > complex, we'll > have to use more specialized selectors. > > Note that same stuff is to be done for Float/Integer coercion: >   | a b c | >   a := 16rFFFFFFFFFFFFF81. >   b := 16rFFFFFFFFFFFFF82. >   c := a asFloat. >   {a = b. >    a = c. >    b = c.} > > Maybe we can also expect advices from other Smalltalkers, and make   > various > dialect response more uniform on such a Kernel subject. > I went on vwnc mailing list with these, but no answer yet. > > Agree ? > > Nicolas > > Le Mardi 28 Mars 2006 12:45, Andreas Raab a écrit : >> Wow. Great catch. Clearly, this is broken. I think we need to change >> this coercion to something that deals with the issue properly (e.g., >> responding false to the comparison in question). Any ideas how to   >> fix that? >> >> Cheers, >>    - Andreas >> > > >
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 OK I put it on http://bugs.impara.de/view.php?id=3374and start to implement my response. Nicolas Le Mardi 28 Mars 2006 22:39, vous avez écrit : > Nicolas > Thanks for all these emails. > Keep going :) > For the compatibility between dialects we should not dream (else we > would not have new calling initialize which is extremely cool as a > teacher and > programmer too). > My feeling is that if we can improve squeak + document the problem > with tests + evaluate how we can move without breaking too much > existing code then we win :) > > Stef
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 In reply to this post by Nicolas Cellier-3 Hello ncellier, Tuesday, March 28, 2006, 7:25:46 AM, you wrote: nic> [number hashing is broken] nic> What is your opinion ? IMHO... sometimes it may be convenient to have 2 = 2.0, but since they represent different intentions, I would not expect that to happen. Why should a perfectly specified integer be equal to, possibly, the result of carrying calculations without infinite precision?  What would it mean if theGreatDoublePrecisionResult = 2?  Wouldn't it be more interesting (and precise) to ask laysWithin: epsilon from: 2? In other words, comparing constants makes it look much simpler than what it really is.  Reading something like anInteger = 2.0 would be, from my point of view, highly questionable because it is an assertion that an approximation has an *exact* value.  Nonsense. >From a more pragmatic point of view, there is also the issue of 2 = 2.0, but things like   (1 bitShift: 1000) - 1 cannot be equal to any floating point number supported by common hardware.  Thus, exploiting anInteger = aFloat is intention obscuring by definition since it may or may not work depending on the integer. Again, highly questionable. In short: floating point numbers *may* be equal to integers, but the behavior of #= cannot be determined a priori.  Since the behavior of #= does not imply a relationship of equivalence, the behavior of #hash is inconsequential. Adding integers and floats to a set gets messed up.  So we have two options... a) don't do it because it is intention obscuring... or b) make integers never be equal to floating point numbers. Same deal with fractions and the like. -- Best regards,  Andres                            mailto:[hidden email]
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 I wholeheartedly agree. We have used tolerance tests for floats since 1962 because equality tests are meaningless. = for floats should give error. Cheers --Trygve At 06:01 29.03.2006,  Andres wrote: >Hello ncellier, > >Tuesday, March 28, 2006, 7:25:46 AM, you wrote: > >nic> [number hashing is broken] >nic> What is your opinion ? > >IMHO... sometimes it may be convenient to have 2 = 2.0, but since they >represent different intentions, I would not expect that to happen. >Why should a perfectly specified integer be equal to, possibly, the >result of carrying calculations without infinite precision?  What >would it mean if theGreatDoublePrecisionResult = 2?  Wouldn't it be >more interesting (and precise) to ask laysWithin: epsilon from: 2? > >In other words, comparing constants makes it look much simpler than >what it really is.  Reading something like anInteger = 2.0 would be, >from my point of view, highly questionable because it is an assertion >that an approximation has an *exact* value.  Nonsense. > > >From a more pragmatic point of view, there is also the issue of 2 = >2.0, but things like > >   (1 bitShift: 1000) - 1 > >cannot be equal to any floating point number supported by common >hardware.  Thus, exploiting anInteger = aFloat is intention obscuring >by definition since it may or may not work depending on the integer. >Again, highly questionable. > >In short: floating point numbers *may* be equal to integers, but the >behavior of #= cannot be determined a priori.  Since the behavior of >#= does not imply a relationship of equivalence, the behavior of #hash >is inconsequential. > >Adding integers and floats to a set gets messed up.  So we have two >options... a) don't do it because it is intention obscuring... or b) >make integers never be equal to floating point numbers. > >Same deal with fractions and the like. > >-- >Best regards, >  Andres                            mailto:[hidden email] -- Trygve Reenskaug      mailto: [hidden email] Morgedalsvn. 5A       http://heim.ifi.uio.no/~trygverN-0378 Oslo           Tel: (+47) 22 49 57 27 Norway
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 In reply to this post by Trygve Reenskaug same here I always use aFloat closeTo: bFloat Stef Trygve Reenskaug wrote: > I wholeheartedly agree. We have used tolerance tests for floats since > 1962 because equality tests are meaningless. = for floats should give > error. >
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 > same here > > I always use > aFloat closeTo: bFloat > > Stef closeTo: is not bad, but 0.0001 accuracy is really something arbitrary. An optional accuracy argument with default value 0.0001 would be better, like Andres suggested: > laysWithin: epsilon from: 2 Back to Andres very clever mail : > In other words, comparing constants makes it look much simpler than > what it really is.  Reading something like anInteger = 2.0 would be, > from my point of view, highly questionable because it is an assertion > that an approximation has an *exact* value.  Nonsense. > That is the very right answer to something i said but did not find satisfying, if not stupid : i said Fraction are more general than Float, so Float could eventually convert to Fraction for doing arithmetics... ksss The other point of view is to say that Float are inexact arithmetic, Fraction and Integer are exact. And in this case, adding something exact with something inexact gives me something inexact. So this is a good reason for converting to Float. Other points were already discussed, and we now have all elements in mind and must make a decision between the three possibilities:   a) let things as is with broken Set and hash       (meaning go to hell with your mixed Set)   b) change int=float to be never true       (implementation very easy, possible nasty side effect in existing code)   c) change int=float to be true only if exact representation are equal       (implementation already on mantis, but great hash code slow down) What is the right place for such a vote ? Squeak chat ? squeak-dev ? mantis ? Nicolas
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 In reply to this post by Andres Valloud Andres Valloud wrote: > IMHO... sometimes it may be convenient to have 2 = 2.0, but since they > represent different intentions, I would not expect that to happen. What about magnitude comparisons (<, >, <=, >=)? For example when using (perfectly well-defined) binary search algorithms on mixed number representations it may be more than merely convenient to have 2 = 2.0. Cheers,    - Andreas > Why should a perfectly specified integer be equal to, possibly, the > result of carrying calculations without infinite precision?  What > would it mean if theGreatDoublePrecisionResult = 2?  Wouldn't it be > more interesting (and precise) to ask laysWithin: epsilon from: 2? > > In other words, comparing constants makes it look much simpler than > what it really is.  Reading something like anInteger = 2.0 would be, > from my point of view, highly questionable because it is an assertion > that an approximation has an *exact* value.  Nonsense. > >>From a more pragmatic point of view, there is also the issue of 2 = > 2.0, but things like > >   (1 bitShift: 1000) - 1 > > cannot be equal to any floating point number supported by common > hardware.  Thus, exploiting anInteger = aFloat is intention obscuring > by definition since it may or may not work depending on the integer. > Again, highly questionable. > > In short: floating point numbers *may* be equal to integers, but the > behavior of #= cannot be determined a priori.  Since the behavior of > #= does not imply a relationship of equivalence, the behavior of #hash > is inconsequential. > > Adding integers and floats to a set gets messed up.  So we have two > options... a) don't do it because it is intention obscuring... or b) > make integers never be equal to floating point numbers. > > Same deal with fractions and the like. >
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 Hello Andreas, Wednesday, March 29, 2006, 6:36:47 PM, you wrote: AR> What about magnitude comparisons (<, >, <=, >=)? For example when AR> using (perfectly well-defined) binary search algorithms on mixed AR> number representations it may be more than merely convenient to AR> have 2 = 2.0. Well... you can use aFloat > 2.0 as well, and in this case expressing intentions clearly would take just two extra characters.  I find it hard to justify lack of proper expression because of unwillingness to type ".0".  And besides it will be faster! :) -- Best regards,  Andres                            mailto:[hidden email]
Open this post in threaded view
|

## Re: Fraction equality and Float infinity problem

 In reply to this post by Andreas.Raab The Scheme community has a process called SRFIs which models on IETF RFCs to explore models and extensions to the standard language (I was one of the founding editors of SRFIs).  Although Scheme is not (usually) OO, it is dynamically typed and has many of the same issues as Smalltalk. In particular, they have recently been discussing many of these issues as part of SRFI-77, at:      http://srfi.schemers.org/srfi-77/In the Document, look at the Issues under the Design Rationalle section. You may also find much of the archived discussion relevant. ../Dave