#FEATURE by cg
class: Integer
added:
#bitDeinterleave:
#bitInterleaveWith:
#bitInterleaveWith:and:
comment/format in: #bitInterleave:
--- a/Integer.st Mon Aug 28 13:54:25 2017 +0200
+++ b/Integer.st Mon Aug 28 15:14:38 2017 +0200
@@ -1660,6 +1660,142 @@
"Modified (comment): / 09-01-2012 / 19:51:00 / cg"
!
+bitDeinterleave:n
+ "extract count integers from an n-way Morton number as a vector;
+ i.e. if count is 3,
+ and the receiver's bits are
+ cN bN aN ... c2 b2 a2 c1 b1 a1 c0 b0 a0
+ then the result will be a vector containing the numbers a,b,c with bits:
+ aN ... a2 a1 a0
+ bN ... b2 b1 b0
+ cN ... c2 c1 c0.
+ This is the inverse operation from bitInterleave:"
+
+ |v shift tuple|
+
+ tuple := Array new:n withAll:0.
+
+ shift := 0.
+ v := self.
+ [ v > 0 ] whileTrue:[
+ 1 to:n do:[:i |
+ tuple at:i put:((tuple at:i) bitOr:((v bitAnd:1) bitShift:shift)).
+ v := v rightShift:1.
+ ].
+ shift := shift + 1.
+ ].
+ ^ tuple
+
+ "
+ (2r1100 bitInterleaveWith:2r1001) -> 2r11100001
+ (2r11000110 bitInterleaveWith:2r10011100 and:2r10100101) -> 2r111100001010010111100001.
+
+ 2r11100001 bitDeinterleave:2
+
+ (2r11000110 bitInterleaveWith:2r10011100 and:2r10100101)
+ (198 bitInterleaveWith:156 and:165) bitDeinterleave:3
+ "
+
+ "Created: / 28-08-2017 / 15:02:31 / cg"
+!
+
+bitInterleaveWith:anInteger
+ "generate a Morton number (-> https://en.wikipedia.org/wiki/Morton_number_(number_theory))
+ by interleaving bits of the receiver (at odd positions if counting from 1)
+ with bits of the argument (at even bit positions).
+
+ Thus, if the bits of the receiver are
+ aN ... a2 a1 a0
+ and those of the argument are:
+ bN ... b2 b1 b0
+ the result is
+ bN aN ... b2 a2 b1 a1 b0 a0.
+
+ Morton numbers are great to linearize 2D coordinates
+ eg. to sort 2D points by distances"
+
+ "/ a naive and slow fallback here, using a small map to process cunks of 4 bits
+
+ |a b shift ma mb val|
+
+ a := self.
+ b := anInteger.
+ val := 0.
+ shift := 0.
+ [ (a == 0) and:[b == 0]] whileFalse:[
+ "/ strip off 4 bits from each...
+ "/ 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
+ mb := #[ 2r00000000 2r00000010 2r00001000 2r00001010 2r00100000 2r00100010 2r00101000 2r00101010 2r10000000 2r10000010 2r10001000 2r10001010 2r10100000 2r10100010 2r10101000 2r10101010 ]
+ at:((b bitAnd:2r1111)+1).
+ ma := #[ 2r00000000 2r00000001 2r00000100 2r00000101 2r00010000 2r00010001 2r00010100 2r00010101 2r01000000 2r01000001 2r01000100 2r01000101 2r01010000 2r01010001 2r01010100 2r01010101 ]
+ at:((a bitAnd:2r1111)+1).
+ val := val bitOr:((ma bitOr:mb) bitShift:shift).
+ shift := shift + 8.
+ a := a rightShift:4.
+ b := b rightShift:4.
+ ].
+ ^ val.
+
+ "
+ (2r11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ bitInterleaveWith:2r10010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
+ -> 2r1101001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+ (2r11000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ bitInterleaveWith:2r10010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
+ -> 2r1101001000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ "
+
+ "Created: / 28-08-2017 / 14:33:08 / cg"
+!
+
+bitInterleaveWith:integer1 and:integer2
+ "generate a Morton3 number (-> https://en.wikipedia.org/wiki/Morton_number_(number_theory))
+ by interleaving bits of the receiver with bits of the arguments.
+ Thus, if the bits of the receiver are
+ aN ... a2 a1 a0
+ and those of the integer1 are:
+ bN ... b2 b1 b0
+ and those of the integer2 are:
+ cN ... c2 c1 c0
+ the result is
+ cN bN aN ... c2 b2 a2 c1 b1 a1 c0 b0 a0.
+
+ Morton3 numbers are great to linearize 3D coordinates
+ eg. to sort 3D points by distances"
+
+ |a b c shift ma mb mc val|
+
+ a := self.
+ b := integer1.
+ c := integer2.
+ val := 0.
+ shift := 0.
+ [ (a == 0) and:[b == 0]] whileFalse:[
+ "/ strip off 4 bits from each...
+ "/ 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
+ mc := #( 2r000000000000 2r000000000100 2r000000100000 2r000000100100 2r000100000000 2r000100000100 2r000100100000 2r000100100100 2r100000000000 2r100000000100 2r100000100000 2r100000100100 2r100100000000 2r100100000100 2r100100100000 2r100100100100 )
+ at:((c bitAnd:2r1111)+1).
+ mb := #( 2r000000000000 2r000000000010 2r000000010000 2r000000010010 2r000010000000 2r000010000010 2r000010010000 2r000010010010 2r010000000000 2r010000000010 2r010000010000 2r010000010010 2r010010000000 2r010010000010 2r010010010000 2r010010010010 )
+ at:((b bitAnd:2r1111)+1).
+ ma := #( 2r000000000000 2r000000000001 2r000000001000 2r000000001001 2r000001000000 2r000001000001 2r000001001000 2r000001001001 2r001000000000 2r001000000001 2r001000001000 2r001000001001 2r001001000000 2r001001000001 2r001001001000 2r001001001001 )
+ at:((a bitAnd:2r1111)+1).
+ val := val bitOr:(((ma bitOr:mb) bitOr:mc) bitShift:shift).
+ shift := shift + 12.
+ a := a rightShift:4.
+ b := b rightShift:4.
+ c := c rightShift:4.
+ ].
+ ^ val.
+
+ "
+ (2r1100 bitInterleaveWith:2r1001 and:2r1010) printStringRadix:2 -> '111 001 100 010'
+ (2r11000110 bitInterleaveWith:2r10011100 and:2r10100101) printStringRadix:2 -> '111 001 100 010 010 111 001 100'
+ "
+
+ "Created: / 28-08-2017 / 14:33:04 / cg"
+!
+
bitInvert
"return a new integer, where all bits are complemented.
This does not really make sense for negative largeIntegers,