5

Given a 64 bit number, I need to extract every other bit from it, and convert it into a number:

decimal:  357
binary:   0000 0001 0110 0101
odd bits:  0 0  0 1  1 0  1 1
decimal:  27

Any idea of a good algorithmic way to do it? And no, not HW, this is for a real world use :)

Yuri Astrakhan
  • 8,808
  • 6
  • 63
  • 97
  • any specific language ? or you need just an algorithm ? – IndieTech Solutions Jun 16 '15 at 02:23
  • In assembler I'd go for a series of Rotate-Right-Through-Carry, exchanging whichever registers you're using for input and output every second shift. I'm not sure how well this would work in a higher level language. –  Jun 16 '15 at 02:30
  • Any language will do. I will probably implement it in JS – Yuri Astrakhan Jun 16 '15 at 02:35
  • 4
    I think you may find this to be a (non-obvious) duplicate to [this](http://stackoverflow.com/questions/3137266/how-to-de-interleave-bits-unmortonizing) - good luck! – J Trana Jun 16 '15 at 03:01
  • Yes, I think it is the same, although the particular method selected there hasn't been proposed here and is different. I first saw that divide and conquer approach in a book by Deo, Nievergelt and Singh (I think I got the names right) on Algorithms. However they used this for counting the number of bits in a word. – rocky Jun 16 '15 at 03:11
  • @Yurik- Whichever answer is clear to you and is correct, I request you to **`upvote`** and **`accept`** the answer. If you have any doubt in my answer, please let me know the same. – Am_I_Helpful Jun 16 '15 at 09:41
  • 2
    @Yurik any language? There are languages where this is one instruction. For example `pext` on modern x86 – harold Jun 16 '15 at 12:57

4 Answers4

4

I would go with performing Arithmetic Right Shift(till the length of the binary number) two at a time. This >> used in my logic is for arithmetic shift.

(Note: In C language, right shifts may or may not be arithmetic!)

Like,

int count=0;
bit=extractLastbit(binary_representation_of_the_number);

while(count!=binaryLength){
  // binaryLength is the length of the binary_representation_of_the_number
  binary_representation_of_the_number=binary_representation_of_the_number>>2;

  bit.appendLeft(extractLastbit(binary_representation_of_the_number);
  count=count+2;
}

where,

extractLastBit() extracts the LSB of the binary number; appendLeft() performs shifting the newly extracted bit to the left of the older bit(s).

Am_I_Helpful
  • 18,735
  • 7
  • 49
  • 73
4

See How to de-interleave bits (UnMortonizing?).

x = x& 0x5555555555555555; //restrict to odd bits.
x = (x | (x >> 1)) & 0x3333333333333333;
x = (x | (x >> 2)) & 0x0f0f0f0f0f0f0f0f;
x = (x | (x >> 4)) & 0x00ff00ff00ff00ff;
x = (x | (x >> 8)) & 0x0000ffff0000ffff;
x = (x | (x >>16)) & 0x00000000ffffffff;
Community
  • 1
  • 1
AShelly
  • 34,686
  • 15
  • 91
  • 152
3

Create a table of 256 entries to look up say each byte. The value of an entry in the table will be the thing converted to a number. Then paste the 4 bytes together with shifts to come up with the final number.

Here is an example scaling things down so you get the idea. The lookup part using 4 bits instead of 8:

0000 = 00
0001 = 01
0010 = 00
0011 = 01
0100 = 10
0101 = 11
...

Looking up say 01010010. Break up into 0101 and 0010. Look those up we get 11, and 00 and paste together: 1100

With a table of 256, you'll need 8 lookups with the corresponding pasting. If you have memory for 2**16 entries then you need only go with four lookups and the pasting is proportionally less too.

The table doesn't have to an even power of two. For example with 1024 entries (2**10) there are 7 lookups. There is just an economy when the table exponent happens to be a power of two (2, 4, 8, 16 or 32).

rocky
  • 7,226
  • 3
  • 33
  • 74
  • and how do you 'create' the table... ? – yurib Jun 16 '15 at 02:36
  • Basically recurse ;-) Instead of working with 64-bit numbers for my table I work with 8-bit numbers. I could make a table of 2 bits each, and use the same method. At some point you can just create the table by hand for the 2 bits. Or use the method by shekhar suman to create the table. If you are going for speed, this is the way to go. If you don't care about speed, then shekhar suman's approach is fine. – rocky Jun 16 '15 at 02:40
  • i was trying to encourage you to add this explanation to you answer :) also, i'm not convinced this approach is faster – yurib Jun 16 '15 at 02:46
  • @yurib if you use 8-bit tables, the time complexity are 4 constant-time lookups and O(4) constant-time operations to join the lookups. For the approach you are thinking of, what is the time complexity? – rocky Jun 16 '15 at 02:50
  • well, assuming we're dealing with number of fixed length (64 bits), i would argue shekhar's approach is also constant - all you're doing is iterating over the individual bits. depending on how you implement the parts of 'breaking' the number into 8 bit blocks and then joining the lookup results back together, i think both approaches are roughly equivalent in terms of run time. – yurib Jun 16 '15 at 02:57
  • May math was wrong with the 8-bit tables, (this is a 64-bit number not 32-bit number). So change 4 to 8. – rocky Jun 16 '15 at 02:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/80620/discussion-between-rocky-and-yurib). – rocky Jun 16 '15 at 03:01
-2

Here's what I eventually came up with - every ODD bit going from/to X value, and every EVEN bit - from/to Y. I had to write it in JavaScript.

function xyToIndex(x, y) {
    // Convert x,y into a single integer with alternating bits
    var mult = 1, result = 0;
    while (x || y) {
        result += (mult * (x % 2));
        x = Math.floor(x / 2);
        mult *= 2;
        result += (mult * (y % 2));
        y = Math.floor(y / 2);
        mult *= 2;
    }
    return result;
}

function indexToXY(index) {
    // Convert a single integer into the x,y coordinates
    // Given a 64bit integer, extract every odd/even bit into two 32bit values
    var x = 0, y = 0, mult = 1;
    while (index) {
        x += mult * (index % 2);
        index = Math.floor(index / 2);
        y += mult * (index % 2);
        index = Math.floor(index / 2);
        mult *= 2;
    }
    return [x, y];
}
Yuri Astrakhan
  • 8,808
  • 6
  • 63
  • 97
  • You could simplify this a lot by using actual bitwise opertators… – Bergi Jun 19 '15 at 01:11
  • Doesn't JS converts float numbers into int32, not int64, so I would loose half the number? – Yuri Astrakhan Jun 19 '15 at 05:33
  • JS doesn't have 64-bit ints so there is nothing you could loose in the first place – Bergi Jun 19 '15 at 05:34
  • According to [http://stackoverflow.com/questions/14731743/how-to-split-64bit-integer-to-two-32bit-integers], JS stores numbers as doubles with 53bits dedicated to the integer part (more than enough for my use case - 2^53 = 9007199254740992). Since the bit operations truncate at 32bit, the division approach should be the best in this case – Yuri Astrakhan Jun 23 '15 at 16:07
  • Yeah, but you'll hardly find yourself using 53 bit data :-) Maybe there are some applications that use 48 bit. – Bergi Jun 23 '15 at 16:16
  • Actually, yes, I do - map tiling - it uses arbitrary number of bits, depending on the zoom level. For zoom 3, you have 4^3 - 64 tiles, addressable by 6 bits number, whereas at zoom 17, that's 34bits number. Combined that with some extra info, like map style ID and overzoom count (3-4 bits), you can have arbitrary number of bits there. – Yuri Astrakhan Jun 25 '15 at 18:27
  • Oh, interesting! I probably would've used a typed array for such purposes, with dedicated views :-) – Bergi Jun 25 '15 at 18:37