[squeak-dev] The Inbox: Kernel-nice.1260.mcz

commits at source.squeak.org commits at source.squeak.org
Tue Aug 20 10:48:04 UTC 2019


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!



More information about the Squeak-dev mailing list