'From Squeak3.10beta of 22 July 2007 [latest update: #7159] on 21 March 2008 at 1:02:32 am'!
"Change Set: Integer_bitAt_M6985-nice
Date: 21 March 2008
Author: nice
Add is a simple feature that is missing:
anInteger bitAt: n answers 1 if nth bit is set to 1, 0 otherwise.
Negatives act as two complements, also LargeNegativeInteger."!
!Integer methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 00:04'!
bitAt: anInteger
"Answer 1 if the bit at position anInteger is set to 1, 0 otherwise.
self is considered an infinite sequence of bits, so anInteger can be any strictly positive integer.
Bit at position 1 is the least significant bit.
Negative numbers are in two-complements.
This is a naive implementation that can be refined in subclass for speed"
^(self bitAnd: (1 bitShift: anInteger - 1)) = 0
ifTrue: [0]
ifFalse: [1]! !
!LargePositiveInteger methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 00:09'!
bitAt: anInteger
"Optimize super algorithm to avoid long bit operations.
Instead work on digits which are known to be SmallInteger and fast.
Note that this algorithm does not work for negative integers."
| digitIndex bitIndex |
digitIndex := anInteger - 1 // 8 + 1.
digitIndex > self digitLength ifTrue: [^0].
bitIndex := anInteger - 1 \\ 8 + 1.
^(self digitAt: digitIndex) bitAt: bitIndex! !
!LargeNegativeInteger methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 01:02'!
bitAt: anInteger
"super would not work because we have to pretend we are in two-complement.
this has to be tricky..."
| digitIndex bitIndex i |
digitIndex := anInteger - 1 // 8 + 1.
digitIndex > self digitLength ifTrue: [^1].
bitIndex := anInteger - 1 \\ 8 + 1.
i := 1.
[i = digitIndex
ifTrue:
["evaluate two complement (bitInvert + 1) on the digit :
(if digitIndex > 1, we must still add 1 due to the carry).
but x bitInvert is -1-x, bitInvert+1 is just x negated..."
^(self digitAt: digitIndex) negated bitAt: bitIndex].
(self digitAt: i) = 0]
whileTrue: [
"two complement (bitInvert + 1) raises a carry:
0 bitInvert -> 2r11111111. 2r11111111 + 1 -> 0 with carry...
Thus we must inquire one digit forward"
i := i + 1].
"We escaped the while loop, because there is no more carry.
Do a simple bitInvert without a carry"
^1 - ((self digitAt: digitIndex) bitAt: bitIndex)! !
!SmallInteger methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 00:36'!
bitAt: anInteger
"Add an heuristic: known to work as long as SmallInteger is on 31 bits...
Otherwise, replace 30 with SmallInteger maxVal highBit"
anInteger > 30 ifTrue: [^self >= 0 ifTrue: [0] ifFalse: [1]].
^super bitAt: anInteger
"A possible alternative: to super bitAt: bitShift operation is:
^(self bitAnd: (#(16r1 16r2 16r4 16r8 16r10 16r20 16r40 16r80
16r100 16r200 16r400 16r800 16r1000 16r2000 16r4000 16r8000
16r10000 16r20000 16r40000 16r80000 16r100000 16r200000 16r400000 16r800000
16r1000000 16r2000000 16r4000000 16r8000000 16r10000000 16r20000000) at: anInteger)) = 0
ifTrue: [0]
ifFalse: [1]"! !