The Inbox: Kernel-nice.1260.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Kernel-nice.1260.mcz

commits-2
Nicolas Cellier uploaded a new version of Kernel to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.1260.mcz

==================== Summary ====================

Name: Kernel-nice.1260
Author: nice
Time: 20 August 2019, 12:47:47.233148 pm
UUID: 71e9900d-adf5-194d-be4b-28fbe395a937
Ancestors: Kernel-nice.1259

Fast-up the SmallInteger/Float comparisons

This is not necessary in 32 bits images, because SmallInteger asFloat is exact, so comparison can be performed exactly by the primitive and is already very fast.

But in 64bits images, SmallInteger asFloat may be inexact. Thus the primitive may fail, reverting to slower adaptToFloat:andCompare:

Though, we can perform the comparison very simply for SmallInteger:

if anInteger asFloat == aFloat
then we are not sure that anInteger asFloat did not introduce a rounding error.
However, in this case, we know that aFloat has no fraction part, and that it can be converted back to Integer exactly (without fear of overflow).
So we just have to perform the comparison the other way around,
        anInteger op: aFloat truncated
       
if anInteger asFloat != aFloat, then we are safe, the rounding error cannot modify the result of operation, so we simply return the result of
        anInteger asFloat op: aFloat
       
I put this in the inbox so as to show and demonstrate the hack, but IMO the right place would be in the primitive (and JIT) because the scheme is simple enough.

=============== Diff against Kernel-nice.1259 ===============

Item was changed:
  ----- Method: SmallInteger>>< (in category 'comparing') -----
  < aNumber
  "Primitive. Compare the receiver with the argument and answer with
  true if the receiver is less than the argument. Otherwise answer false.
  Fail if the argument is not a SmallInteger. Essential. No Lookup. See
  Object documentation whatIsAPrimitive."
 
  <primitive: 3>
+ aNumber isFloat ifTrue: [| asFloat |
+ ^(asFloat := self asFloat) = aNumber
+ ifTrue: [self < aNumber truncated]
+ ifFalse: [asFloat < aNumber] ].
  ^super < aNumber!

Item was changed:
  ----- Method: SmallInteger>><= (in category 'comparing') -----
  <= aNumber
  "Primitive. Compare the receiver with the argument and answer true if
  the receiver is less than or equal to the argument. Otherwise answer
  false. Fail if the argument is not a SmallInteger. Optional. No Lookup.
  See Object documentation whatIsAPrimitive. "
 
  <primitive: 5>
+ aNumber isFloat ifTrue: [| asFloat |
+ ^(asFloat := self asFloat) = aNumber
+ ifTrue: [self <= aNumber truncated]
+ ifFalse: [asFloat <= aNumber] ].
  ^super <= aNumber!

Item was changed:
  ----- Method: SmallInteger>>= (in category 'comparing') -----
  = aNumber
  "Primitive. Compare the receiver with the argument and answer true if
  the receiver is equal to the argument. Otherwise answer false. Fail if the
  argument is not a SmallInteger. Essential. No Lookup. See Object
  documentation whatIsAPrimitive. "
 
  <primitive: 7>
+ aNumber isFloat ifTrue: [ ^self asFloat = aNumber and: [self = aNumber truncated] ].
  ^super = aNumber!

Item was changed:
  ----- Method: SmallInteger>>> (in category 'comparing') -----
  > aNumber
  "Primitive. Compare the receiver with the argument and answer true if
  the receiver is greater than the argument. Otherwise answer false. Fail if
  the argument is not a SmallInteger. Essential. No Lookup. See Object
  documentation whatIsAPrimitive."
 
  <primitive: 4>
+ aNumber isFloat ifTrue: [| asFloat |
+ ^(asFloat := self asFloat) = aNumber
+ ifTrue: [self > aNumber truncated]
+ ifFalse: [asFloat > aNumber] ].
  ^super > aNumber!

Item was changed:
  ----- Method: SmallInteger>>>= (in category 'comparing') -----
  >= aNumber
  "Primitive. Compare the receiver with the argument and answer true if
  the receiver is greater than or equal to the argument. Otherwise answer
  false. Fail if the argument is not a SmallInteger. Optional. No Lookup.
  See Object documentation whatIsAPrimitive."
 
  <primitive: 6>
+ aNumber isFloat ifTrue: [| asFloat |
+ ^(asFloat := self asFloat) = aNumber
+ ifTrue: [self >= aNumber truncated]
+ ifFalse: [asFloat >= aNumber] ].
  ^super >= aNumber!

Item was added:
+ ----- Method: SmallInteger>>adaptToFloat:andCompare: (in category 'converting') -----
+ adaptToFloat: rcvr andCompare: selector
+ "If I am involved in comparison with a Float, care to perform an exact comparison of values."
+
+ | asFloat |
+ "First try cheap asFloat conversion.
+ There is no comparison ambiguity when self does not round to same Float value"
+ asFloat := self asFloat.
+ (rcvr ~= asFloat or: [self isAnExactFloat]) ifTrue: [^rcvr perform: selector with: asFloat].
+ "rcvr and self are not equal because self is not an exact Float, but self round to same Float value.
+ It is necessary to convert the Float to an exact representation so as to perform the compariosn without rounding error.
+ We know that the Float has no fractionPart because it is equal to self asFloat, and self asFloat has no fractionPart.
+ Thus we can use truncated which is faster than asTrueFraction."
+ selector == #= ifTrue: [^false].
+ selector == #~= ifTrue: [^true].
+ ^ rcvr truncated perform: selector with: self!