I tested this:
| x |
x := SmallInteger maxVal raisedToInteger: 100.
{Time millisecondsToRun: [100000 timesRepeat: [x byteShift: -200]].
Time millisecondsToRun: [100000 timesRepeat: [x bitShift: -1600]].
Time millisecondsToRun: [100000 timesRepeat: [x bitShift: -1597]]}.
And got that:
#(95 164 172)
That means that case of exact byte boundary is not optimized for Rshift.
As shown below, it is optimized for LShift:
| x |
x := SmallInteger maxVal raisedToInteger: 100.
{Time millisecondsToRun: [100000 timesRepeat: [x byteShift: 200]].
Time millisecondsToRun: [100000 timesRepeat: [x bitShift: 1600]].
Time millisecondsToRun: [100000 timesRepeat: [x bitShift: 1597]]}.
#(103 120 315)
Notice that Rshift seems more efficient than Lshift on non byte boundary (nBits
\\ 8 ~= 0)...
Well, speed factor is not major (<2) but I would expect performance from these
low level primitives...
Ah, the byteShift: code is here if you wanna try:
LargePositiveInteger>>byteShift: n
"shift by bytes, which is faster than bits when n < 0"
| shifted |
n = 0 ifTrue: [^ self].
n > 0 ifTrue: [
shifted := self class new: self digitLength + n.
shifted replaceFrom: n+1 to: self digitLength + n with: self startingAt: 1.
^ shifted].
self digitLength + n <= 0 ifTrue: [^0].
shifted := self class new: self digitLength + n.
shifted replaceFrom: 1 to: self digitLength + n with: self startingAt: 1 - n.
^ shifted normalize
Which could also be written:
LargePositiveInteger>>byteShift: n
"shift by bytes, which is faster than bits when n < 0"
| shifted |
n = 0 ifTrue: [^ self].
self digitLength + n <= 0 ifTrue: [^0].
shifted := self class new: self digitLength + n.
shifted replaceFrom: (1 max: 1 + n) to: self digitLength + n with: self
startingAt: (1 max: 1 - n).
^ shifted normalize