13

While reading this: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv

I came to the phrase:

The last step, which involves modulus division by 2^10 - 1, has the effect of merging together each set of 10 bits (from positions 0-9, 10-19, 20-29, ...) in the 64-bit value.

(it is about reversing the bits in a number)...

so I did some calculations:

reverted = (input * 0x0202020202ULL & 0x010884422010ULL) % 1023;

b = 74          :                                 01001010
b 
 * 0x0202020202 :       1000000010000000100000001000000010
   = 9494949494 :01001010010010100100101001001010010010100
  & 10884422010 :10000100010000100010000100010000000010000 
    = 84000010  :         10000100000000000000000000010000
  % 1023        :                               1111111111
    = 82        :                                 01010010

Now, the only part which is somewhat unclear is the part where the big number modulo by 1023 (2^10 - 1) packs and gives me the inverted bits... I did not find any good doc about relationship between bit operations and the modulo operation (beside x % 2^n == x & (2^n - 1))) so maybe if someone would cast a light on this it would be very fruitful.

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • 1
    The modulo doesn't "invert" the bits, it just "packs" the 4 bytes into one. – user703016 Mar 10 '14 at 12:43
  • @RagingScallion You're right, bad wording from my side... – Ferenc Deak Mar 10 '14 at 12:44
  • 1
    Just FYI, division operations (such as modulo) are very expensive on a CPU with fixed-point architecture. Now, you tagged your question as `low-level`, so I assume that it might be relevant in your case. If you **are** writing your code for that kind of processor, then you should really try to avoid using `%` or `/` (as I said, just FYI)... In addition, you may also want to look at http://aggregate.org/MAGIC/#Bit%20Reversal (no division operations involved). Although it shows an example for a 32-bit operand, I believe it should work fine for 64-bit operands as well. – barak manos Mar 10 '14 at 13:01
  • 1
    N mod constant should not be expensive at all; the compiler can use similar trick to turn the division into reciprocal multiplication and more. – Aki Suihkonen Mar 11 '14 at 17:47
  • " I did not find any good doc about relationship between bit operations and the modulo operation (beside x % 2^n == x & (2^n - 1))) " -- what more do you want? – Jim Balter Sep 27 '14 at 05:46

1 Answers1

7

The modulo operation does not give you the inverted bits per se, it is just a binning operation.

First Line : word expansion

b * 0x0202020202 = 01001010 01001010 01001010 01001010 01001010 0

The multiplication operation has a convolution property, which means it replicate the input variable several times (5 here since it's a 8-bit word).

First Line : reversing bits

That's the most tricky part of the hack. You have to remember that we are working on a 8-bit word : b = abcdefgh, where [a-h] are either 1 or 0.

b  * 0x0202020202 = abcdefghabcdefghabcdefghabcdefghabcdefgha
    & 10884422010 = a0000f000b0000g000c0000h000d00000000e0000

Last Line : word binning

Modulo has a peculiar property : 10 ≡ 1 (mod 9) so 100 ≡ 10*10 ≡ 10*1 (mod 9) ≡ 1 (mod 9).

More generally, for a base b, b ≡ 1 (mod b - 1) so for all number a ≡ sum(a_k*b^k) ≡ sum (a_k) (mod b - 1).

In the example, base = 1024 (10 bits) so

b ≡ a0000f000b0000g000c0000h000d00000000e0000 
  ≡ a*base^4 + 0000f000b0*base^3 + 000g000c00*base^2 + 00h000d000*base +00000e0000 
  ≡ a + 0000f000b0 + 000g000c00 + 00h000d000 + 00000e0000 (mod b - 1)
  ≡  000000000a
   + 0000f000b0 
   + 000g000c00 
   + 00h000d000 
   + 00000e0000 (mod b - 1)
 ≡   00hgfedcba (mod b - 1) since there is no carry (no overlap)
lucasg
  • 10,734
  • 4
  • 35
  • 57