"Try this: you get size of 2"
| q qf q2 | q := 12346548789456/346874324768747. qf := q asFloat. q2 := qf asTrueFraction. (Set with: q with: qf with: q2) size. "Then try this, you get size of 1" | q qf q2 | q := 12346548789456/346874324768747. qf := q asFloat. q2 := qf asTrueFraction. (Set with: qf with: q with: q2) size "What's wrong ?" I already discussed this on squeak-dev, the problem is that Float should not equal a Fraction, except self asTrueFraction, otherwise equality is no more transitive. Same can be illustrated with LargeInteger... See http://bugs.impara.de/view.php?id=3374, where i propose converting Float asTrueFraction in order to compare Float to Integer and Fraction, instead of converting Integer and Fraction asFloat... Only comparison operators (= ~= < <= > >=) should use asTrueFraction conversion. Arithmetic + * - / should still convert asFloat. Rationale: mixing exact (Integer or Fraction) arithmetic with inexact (Float) arithmetic give an inexact result (Float). Nicolas |
I attach a proposition to handle Float/Fraction/Integer equality in a
way preserving transitivity property. Now we can have two numbers such that (a-b) isZero is true - due to inexact arithmetic, but (a = b) is false. Nicolas | package | package := Package name: 'FloatComparePatch'. package paxVersion: 1; basicComment: ''. package methodNames add: #ArithmeticValue -> #compareWithFloat:; add: #ArithmeticValue -> #compareWithFraction:; add: #ArithmeticValue -> #compareWithInteger:; add: #Float -> #=; add: #Float -> #compareWithFraction:; add: #Float -> #compareWithInteger:; add: #Float -> #greaterThanFraction:; add: #Float -> #greaterThanInteger:; add: #Fraction -> #=; add: #Fraction -> #compareWithFloat:; add: #Fraction -> #greaterThanFloat:; add: #Integer -> #=; add: #Integer -> #compareWithFloat:; add: #Integer -> #greaterThanFloat:; yourself. package binaryGlobalNames: (Set new yourself). package globalAliases: (Set new yourself). package setPrerequisites: (IdentitySet new add: 'Object Arts\Dolphin\Base\Dolphin'; yourself). package! "Class Definitions"! "Global Aliases"! "Loose Methods"! !ArithmeticValue methodsFor! compareWithFloat: aFloat ^(self - aFloat) isZero! compareWithFraction: aFraction ^(self - aFraction) isZero! compareWithInteger: anInteger ^(self - anInteger) isZero! ! !ArithmeticValue categoriesFor: #compareWithFloat:!double dispatch!public! ! !ArithmeticValue categoriesFor: #compareWithFraction:!double dispatch!public! ! !ArithmeticValue categoriesFor: #compareWithInteger:!double dispatch!public! ! !Float methodsFor! = comperand "Answer whether the receiver is numerically equivalent to the argument, comperand (e.g. 1 = 1.0 is true). Primitive failure reasons: 0 - aNumber is not a SmallInteger or a Float. May also raise a floating point exception." <primitive: 163> ^comperand understandsArithmetic and: [comperand compareWithFloat: self] "^super = comperand"! compareWithFraction: aFraction ^self asTrueFraction = aFraction! compareWithInteger: anInteger ^self asTrueFraction = anInteger! greaterThanFraction: aFraction "Private - Answer whether the receiver is greater than the known Fraction, aFraction." ^aFraction < self asTrueFraction! greaterThanInteger: anInteger "Private - Answer whether the receiver is greater than the known Integer, anInteger." ^anInteger < self asTrueFraction! ! !Float categoriesFor: #=!comparing!public! ! !Float categoriesFor: #compareWithFraction:!double dispatch!public! ! !Float categoriesFor: #compareWithInteger:!double dispatch!public! ! !Float categoriesFor: #greaterThanFraction:!double dispatch!private! ! !Float categoriesFor: #greaterThanInteger:!double dispatch!private! ! !Fraction methodsFor! = comparand ^comparand understandsArithmetic and: [comparand compareWithFraction: self]! compareWithFloat: aFloat ^aFloat asTrueFraction = self! greaterThanFloat: aFloat "Private - Answer whether the receiver is greater than the known Float, aFloat" ^aFloat asTrueFraction < self! ! !Fraction categoriesFor: #=!comparing!public! ! !Fraction categoriesFor: #compareWithFloat:!double dispatch!public! ! !Fraction categoriesFor: #greaterThanFloat:!double dispatch!private! ! !Integer methodsFor! = comparand ^comparand understandsArithmetic and: [comparand compareWithInteger: self]! compareWithFloat: aFloat ^aFloat asTrueFraction = self! greaterThanFloat: aFloat "Private - Answer whether the receiver is greater than the known Float, aFloat." ^aFloat asTrueFraction < self! ! !Integer categoriesFor: #=!comparing!public! ! !Integer categoriesFor: #compareWithFloat:!double dispatch!public! ! !Integer categoriesFor: #greaterThanFloat:!double dispatch!private! ! "End of package definition"! "Source Globals"! "Classes"! "Binary Globals"! |
Free forum by Nabble | Edit this page |