Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.398.mcz ==================== Summary ==================== Name: Kernel-nice.398 Author: nice Time: 13 February 2010, 4:31:00.389 am UUID: f1525362-d01a-214c-94fe-2bb3a5fffa89 Ancestors: Kernel-nice.397 Fix http://bugs.squeak.org/view.php?id=3360 http://bugs.squeak.org/view.php?id=3374 http://bugs.squeak.org/view.php?id=6601 hash and = are now reconciled for numbers. = is now transitive for numbers. WARNING: now, tests like (1/10 = 0.1) will answer false. This is expected, and more than expected, this is wanted. Float are inexact and testing for strict equality is not a clever thing to do. All this has been longly debated at http://permalink.gmane.org/gmane.comp.lang.smalltalk.pharo.devel/10642 http://thread.gmane.org/gmane.comp.lang.smalltalk.sapphire.devel/10223/focus=10228 Please, read carefully this thread to make an opinion before raising your voice. It can break code eventually, so I'm all ears to real case, and willing to help fixing. But please, real examples, not theoretical (after 8 month change in Pharo, I'm not aware of further complaints). =============== Diff against Kernel-nice.397 =============== Item was changed: ----- Method: ScaledDecimal>><= (in category 'comparing') ----- <= operand "Implementation of Number 'comparing' method." (operand isKindOf: ScaledDecimal) ifTrue: [^ fraction <= operand asFraction]. + ^ operand adaptToScaledDecimal: self andCompare: #<=! - ^ operand adaptToScaledDecimal: self andSend: #<=! Item was added: + ----- Method: Float>>adaptToScaledDecimal:andCompare: (in category 'converting') ----- + adaptToScaledDecimal: rcvr andCompare: selector + "If I am involved in comparison with a scaled Decimal, convert myself to a + Fraction. This way, no bit is lost and comparison is exact." + + self isFinite + ifFalse: [ + selector == #= ifTrue: [^false]. + selector == #~= ifTrue: [^true]. + self isNaN ifTrue: [^ false]. + (selector = #< or: [selector = #'<=']) + ifTrue: [^ self positive]. + (selector = #> or: [selector = #'>=']) + ifTrue: [^ self positive not]. + ^self error: 'unknow comparison selector']. + + ^ rcvr perform: selector with: self asTrueFraction! Item was changed: ----- Method: Integer>>>= (in category 'comparing') ----- >= aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^(self digitCompare: aNumber) <= 0] ifFalse: [^(self digitCompare: aNumber) >= 0]] ifFalse: [^ aNumber negative]]. + ^ aNumber adaptToInteger: self andCompare: #>=! - ^ aNumber adaptToInteger: self andSend: #>=! Item was changed: ----- Method: Float>>>= (in category 'comparing') ----- >= aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is greater than or equal to the argument. Otherwise return false. Fail if the argument is not a Float. Optional. See Object documentation whatIsAPrimitive. " <primitive: 46> + ^ aNumber adaptToFloat: self andCompare: #>=! - ^ aNumber adaptToFloat: self andSend: #>=! Item was changed: ----- Method: ScaledDecimal>>< (in category 'comparing') ----- < operand "Implementation of Number 'comparing' method." (operand isKindOf: ScaledDecimal) ifTrue: [^ fraction < operand asFraction]. + ^ operand adaptToScaledDecimal: self andCompare: #<! - ^ operand adaptToScaledDecimal: self andSend: #<! Item was changed: ----- Method: Fraction>>>= (in category 'comparing') ----- >= aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator >= (aNumber numerator * denominator)]. + ^ aNumber adaptToFraction: self andCompare: #>=! - ^ aNumber adaptToFraction: self andSend: #>=! Item was changed: ----- Method: ScaledDecimal>>= (in category 'comparing') ----- = comparand "Implementation of Number 'comparing' method." comparand isNumber ifFalse: [^ false]. (comparand isKindOf: ScaledDecimal) ifTrue: [^ fraction = comparand asFraction]. + ^ comparand adaptToScaledDecimal: self andCompare: #=! - ^ comparand adaptToScaledDecimal: self andSend: #=! Item was changed: ----- Method: ScaledDecimal>>> (in category 'comparing') ----- > operand "Implementation of Number 'comparing' method." (operand isKindOf: ScaledDecimal) ifTrue: [^ fraction > operand asFraction]. + ^ operand adaptToScaledDecimal: self andCompare: #>! - ^ operand adaptToScaledDecimal: self andSend: #>! Item was added: + ----- Method: Float>>adaptToInteger:andCompare: (in category 'converting') ----- + adaptToInteger: rcvr andCompare: selector + "If I am involved in comparison with an Integer, convert myself to a + Fraction. This way, no bit is lost and comparison is exact." + + self isFinite + ifFalse: [ + selector == #= ifTrue: [^false]. + selector == #~= ifTrue: [^true]. + self isNaN ifTrue: [^ false]. + (selector = #< or: [selector = #'<=']) + ifTrue: [^ self positive]. + (selector = #> or: [selector = #'>=']) + ifTrue: [^ self positive not]. + ^self error: 'unknow comparison selector']. + + "Try to avoid asTrueFraction because it can cost" + selector == #= ifTrue: [ + self fractionPart = 0.0 ifFalse: [^false]]. + selector == #~= ifTrue: [ + self fractionPart = 0.0 ifFalse: [^true]]. + + ^ rcvr perform: selector with: self asTrueFraction! Item was added: + ----- Method: Object>>adaptToFraction:andCompare: (in category 'converting') ----- + adaptToFraction: rcvr andCompare: selector + "If I am involved in comparison with a Fraction. + Default behaviour is to process comparison as any other selectors." + ^ self adaptToFraction: rcvr andSend: selector! Item was added: + ----- Method: Number>>adaptToFloat:andCompare: (in category 'converting') ----- + adaptToFloat: rcvr andCompare: selector + "If I am involved in comparison with a Float, convert rcvr to a + Fraction. This way, no bit is lost and comparison is exact." + + rcvr isFinite + ifFalse: [ + selector == #= ifTrue: [^false]. + selector == #~= ifTrue: [^true]. + rcvr isNaN ifTrue: [^ false]. + (selector = #< or: [selector = #'<=']) + ifTrue: [^ rcvr positive not]. + (selector = #> or: [selector = #'>=']) + ifTrue: [^ rcvr positive]. + ^self error: 'unknow comparison selector']. + + ^ rcvr asTrueFraction perform: selector with: self! Item was changed: ----- Method: Float>>hash (in category 'comparing') ----- hash + "Hash is reimplemented because = is implemented. Both words of the float are used. (The bitShift:'s ensure that the intermediate results do not become a large integer.) Care is taken to answer same hash as an equal Integer." - "Hash is reimplemented because = is implemented. Both words of the float are used; 8 bits are removed from each end to clear most of the exponent regardless of the byte ordering. (The bitAnd:'s ensure that the intermediate results do not become a large integer.) Slower than the original version in the ratios 12:5 to 2:1 depending on values. (DNS, 11 May, 1997)" + (self isFinite and: [self fractionPart = 0.0]) ifTrue: [^self truncated hash]. + ^ ((self basicAt: 1) bitShift: -4) + + ((self basicAt: 2) bitShift: -4) - ^ (((self basicAt: 1) bitAnd: 16r00FFFF00) + - ((self basicAt: 2) bitAnd: 16r00FFFF00)) bitShift: -8 ! Item was added: + ----- Method: Object>>adaptToFloat:andCompare: (in category 'converting') ----- + adaptToFloat: rcvr andCompare: selector + "If I am involved in comparison with a Float. + Default behaviour is to process comparison as any other selectors." + ^ self adaptToFloat: rcvr andSend: selector! Item was changed: ----- Method: Fraction>>hash (in category 'comparing') ----- hash + "Hash is reimplemented because = is implemented. + Care is taken that a Fraction equal to a Float also have an equal hash" - "Hash is reimplemented because = is implemented." + | tmp | + denominator isPowerOfTwo ifTrue: [ + "If denominator is a power of two, I can be exactly equal to a Float + Assume the fraction is already reduced" + tmp := self asFloat. + tmp isFinite ifTrue: [^tmp hash]]. ^numerator hash bitXor: denominator hash! Item was changed: ----- Method: Integer>><= (in category 'comparing') ----- <= aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^ (self digitCompare: aNumber) >= 0] ifFalse: [^ (self digitCompare: aNumber) <= 0]] ifFalse: [^ self negative]]. + ^ aNumber adaptToInteger: self andCompare: #<=! - ^ aNumber adaptToInteger: self andSend: #<=! Item was added: + ----- Method: Object>>adaptToScaledDecimal:andCompare: (in category 'converting') ----- + adaptToScaledDecimal: rcvr andCompare: selector + "If I am involved in comparison with a ScaledDecimal. + Default behaviour is to process comparison as any other selectors." + ^ self adaptToScaledDecimal: rcvr andSend: selector! Item was changed: ----- Method: Float>><= (in category 'comparing') ----- <= aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is less than or equal to the argument. Otherwise return false. Fail if the argument is not a Float. Optional. See Object documentation whatIsAPrimitive." <primitive: 45> + ^ aNumber adaptToFloat: self andCompare: #<=! - ^ aNumber adaptToFloat: self andSend: #<=! Item was changed: ----- Method: Fraction>><= (in category 'comparing') ----- <= aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator <= (aNumber numerator * denominator)]. + ^ aNumber adaptToFraction: self andCompare: #<=! - ^ aNumber adaptToFraction: self andSend: #<=! Item was changed: ----- Method: Integer>>< (in category 'comparing') ----- < aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^ (self digitCompare: aNumber) > 0] ifFalse: [^ (self digitCompare: aNumber) < 0]] ifFalse: [^ self negative]]. + ^ aNumber adaptToInteger: self andCompare: #<! - ^ aNumber adaptToInteger: self andSend: #<! Item was changed: ----- Method: ScaledDecimal>>>= (in category 'comparing') ----- >= operand "Implementation of Number 'comparing' method." (operand isKindOf: ScaledDecimal) ifTrue: [^ fraction >= operand asFraction]. + ^ operand adaptToScaledDecimal: self andCompare: #>=! - ^ operand adaptToScaledDecimal: self andSend: #>=! Item was changed: ----- Method: Integer>>= (in category 'comparing') ----- = aNumber aNumber isNumber ifFalse: [^ false]. aNumber isInteger ifTrue: [aNumber negative == self negative ifTrue: [^ (self digitCompare: aNumber) = 0] ifFalse: [^ false]]. + ^ aNumber adaptToInteger: self andCompare: #=! - ^ aNumber adaptToInteger: self andSend: #=! Item was changed: ----- Method: Integer>>> (in category 'comparing') ----- > aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^(self digitCompare: aNumber) < 0] ifFalse: [^(self digitCompare: aNumber) > 0]] ifFalse: [^ aNumber negative]]. + ^ aNumber adaptToInteger: self andCompare: #>! - ^ aNumber adaptToInteger: self andSend: #>! Item was changed: ----- Method: Float>>< (in category 'comparing') ----- < aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is less than the argument. Otherwise return false. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 43> + ^ aNumber adaptToFloat: self andCompare: #<! - ^ aNumber adaptToFloat: self andSend: #<! Item was changed: ----- Method: Fraction>>< (in category 'comparing') ----- < aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator < (aNumber numerator * denominator)]. + ^ aNumber adaptToFraction: self andCompare: #<! - ^ aNumber adaptToFraction: self andSend: #<! Item was changed: ----- Method: Float>>= (in category 'comparing') ----- = aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is equal to the argument. Otherwise return false. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 47> aNumber isNumber ifFalse: [^ false]. + ^ aNumber adaptToFloat: self andCompare: #=! - ^ aNumber adaptToFloat: self andSend: #=! Item was changed: ----- Method: Fraction>>= (in category 'comparing') ----- = aNumber aNumber isNumber ifFalse: [^ false]. aNumber isFraction ifTrue: [numerator = 0 ifTrue: [^ aNumber numerator = 0]. ^ (numerator * aNumber denominator) = (aNumber numerator * denominator) "Note: used to just compare num and denom, but this fails for improper fractions"]. + ^ aNumber adaptToFraction: self andCompare: #=! - ^ aNumber adaptToFraction: self andSend: #=! Item was added: + ----- Method: Object>>adaptToInteger:andCompare: (in category 'converting') ----- + adaptToInteger: rcvr andCompare: selector + "If I am involved in comparison with an Integer. + Default behaviour is to process comparison as any other selectors." + ^ self adaptToInteger: rcvr andSend: selector! Item was added: + ----- Method: Float>>adaptToFraction:andCompare: (in category 'converting') ----- + adaptToFraction: rcvr andCompare: selector + "If I am involved in comparison with a Fraction, convert myself to a + Fraction. This way, no bit is lost and comparison is exact." + + self isFinite + ifFalse: [ + selector == #= ifTrue: [^false]. + selector == #~= ifTrue: [^true]. + self isNaN ifTrue: [^ false]. + (selector = #< or: [selector = #'<=']) + ifTrue: [^ self positive]. + (selector = #> or: [selector = #'>=']) + ifTrue: [^ self positive not]. + ^self error: 'unknow comparison selector']. + + "Try to avoid asTrueFraction because it can cost" + selector == #= ifTrue: [ + rcvr denominator isPowerOfTwo ifFalse: [^false]]. + selector == #~= ifTrue: [ + rcvr denominator isPowerOfTwo ifFalse: [^true]]. + + ^ rcvr perform: selector with: self asTrueFraction! Item was changed: ----- Method: Float>>> (in category 'comparing') ----- > aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is greater than the argument. Otherwise return false. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 44> + ^ aNumber adaptToFloat: self andCompare: #>! - ^ aNumber adaptToFloat: self andSend: #>! Item was changed: ----- Method: Fraction>>> (in category 'comparing') ----- > aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator > (aNumber numerator * denominator)]. + ^ aNumber adaptToFraction: self andCompare: #>! - ^ aNumber adaptToFraction: self andSend: #>! |
Free forum by Nabble | Edit this page |