[squeak-dev] The Trunk: Kernel-nice.1428.mcz

commits at source.squeak.org commits at source.squeak.org
Sun Nov 28 21:44:47 UTC 2021

Nicolas Cellier uploaded a new version of Kernel to project The Trunk:

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

Name: Kernel-nice.1428
Author: nice
Time: 28 November 2021, 10:44:44.154815 pm
UUID: a8a214a1-7879-4782-8dd7-910f183fda65
Ancestors: Kernel-nice.1427

Simplify code for integer division, and marginally fast up some edge case like (SmallInteger / LargeInteger)

Integer was trying to handle case of exact division (Integer / Integer) by performing a quorem operation (digitDiv:neg:), in the hope that avoiding the creation of an unecessary Fraction intermediate would fast things up.

But it appears that digitDiv:neg: does no good nowadays.
- primitive 10 for SmallInteger/SmallInteger case,
- primitive 30 for Integer/Integer case (up to 64 bits)
already handle exact division (their sole purpose if they exist!).

If 10 & 30 are not implemented (they are optional), probably we do not care that much about such micro optimization anyway.

in mixed cases:
- (SmallInteger / LargeInteger), division cannot be exact - except for 0 receiver, so we're just wasting time

Anyway, digitDiv:neg: creates a LargeInteger object for each SmallInteger receiver/argument, and an Array for the resulting quotient and remainder, so in term of creating intermediate objects, it's not much better.
It is also pure waste of time if division is inexact - and division tend to not be cheap for LargeInteger.
Also, gcd: algorithm used in Fraction>>#reduced performs well enough in the case of exact division.

While at it, only handle zero divide in Integer/Integer case.
Let further dispatching handle the case for mixed Integer/Number arithmetic (Integer shall mind its own business).
Note that Fraction>>#setNumerator:denominator: already signal the ZeroDivide, but would not resume: correctly (we send #reduced to the result, which assumes that it is a Fraction)

Warning: benchmarking and understanding the marginal fast-up is not easy, because we have:
- a special bytecode for division
- special primitive for 64 bits integer range
- jit for some of those primitives
that's many cases.

Thanks to https://github.com/pharo-project/pharo/pull/10385 for asking.

=============== Diff against Kernel-nice.1427 ===============

Item was changed:
  ----- Method: Integer>>/ (in category 'arithmetic') -----
  / aNumber
  	"Refer to the comment in Number / "
- 	| quoRem |
  	aNumber isInteger ifTrue:
+ 		[aNumber isZero
+ 			ifTrue: [^(ZeroDivide dividend: self) signal].
+ 		^ (Fraction numerator: self denominator: aNumber) reduced].
- 		[quoRem := self divideByInteger: aNumber.
- 		(quoRem at: 2) = 0
- 			ifTrue: [^ (quoRem at: 1) normalize]
- 			ifFalse: [^ (Fraction numerator: self denominator: aNumber) reduced]].
  	^ aNumber adaptToInteger: self andSend: #/!

Item was changed:
  ----- Method: SmallInteger>>/ (in category 'arithmetic') -----
  / aNumber 
  	"Primitive. This primitive (for /) divides the receiver by the argument
  	and returns the result if the division is exact. Fail if the result is not a
  	whole integer. Fail if the argument is 0 or is not a SmallInteger. Optional.
  	No Lookup. See Object documentation whatIsAPrimitive."
  	<primitive: 10>
+ 	^super / aNumber!
- 	aNumber isZero ifTrue: [^(ZeroDivide dividend: self) signal].
- 	^(aNumber isMemberOf: SmallInteger)
- 		ifTrue: [(Fraction numerator: self denominator: aNumber) reduced]
- 		ifFalse: [super / aNumber]!

More information about the Squeak-dev mailing list