4

I can't seem to find any bit magic on this, so i was hoping someone here might be able to shed a little light on if this is even possible.

I'm trying to find the number of bitwise transitions in an 8 bit integer (the integer is actually a 32 bit integer, but i'm only using the first 8 bits) to determine if the 8 bits are uniform (2 or less transitions).

For example:

00100000 - two transitions - uniform
00100001 - three transitions - not uniform
10101010 - seven transitions - not uniform
00000000 - no transitions - uniform

Is there a faster way to find the number of transitions other than looping through each bit (looping through each bit is currently the only solution i can come up with)?

iedoc
  • 2,266
  • 3
  • 30
  • 53
  • uniform distribution i think you would call it? basically, if there is less than 2 transitions in a sequence of 8 bits, that is what i am calling uniform – iedoc Feb 23 '16 at 16:32
  • Oh, I get it! Transition happens when a bit changes value in the bit-array. Me smart! – Dialecticus Feb 23 '16 at 16:33
  • how does bit pattern with 3 or more transition correspond less to a uniform distribution than one with 2 or less? I dont really understand how this is related to uniform distributions. – 463035818_is_not_an_ai Feb 23 '16 at 16:34
  • ok, to be clear of it's use, it is to remove a little noise in image processing. each of the bits are basically an edge or not. if there are too many "transitions" in the sequence, it could generally be considered "noise", and will not be taken into consideration. maybe uniform distribution is not the right way to say it? – iedoc Feb 23 '16 at 16:36
  • 3
    Since it is 8 bit integer, why don't you just do a lookup table. – invisal Feb 23 '16 at 16:40
  • btw I think the number of transitions is not the best criteria to look for edgges. E.g. `01111111`. has one transition, but if the byte before is `11111111`, then the first zero is probably noise... – 463035818_is_not_an_ai Feb 24 '16 at 09:34

2 Answers2

7

You can x-or the value with the value shifted by one bit and then count the number of 1 in the result.

unsigned v = (x ^ (x>>1)) & 0x7F;
unsigned count = 0;
while (v) {
    count++;
    v &= (v - 1);
}

Note also that a byte can only have 256 configurations, so the computation can be done once and put in a very small table of 256 bytes.

If you just want to know if there are 2 or less changes the loop can be unrolled:

unsigned v = (x ^ (x >> 1)) & 0x7F;
v &= v - 1;
v &= v - 1;
uniform = (v == 0);

Note that this computation is independent on how big is the number and you can use for example directly a 32-bit unsigned number (the only thing that changes is the mask that becomes 0x7FFFFFFF)

6502
  • 112,025
  • 15
  • 165
  • 265
  • This will work, and maybe it's the fastest solution possible? i mean there are only 8 bits, so this could easily be compiled into a small number of instruction. I guess my real question was what is the fastest way to do it. I'll mark this as the answer shortly if nobody has responded with a better way. thanks! – iedoc Feb 23 '16 at 16:38
  • 3
    Well, a lookup table will be fast, @iedoc, but a `while` loop certainly won't. If you don't want to use a lookup table, counting the number of set bits is a common problem, with [lots of well-known solutions](http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer). – Cody Gray - on strike Feb 23 '16 at 16:41
  • The lookup table is a great solution. I think thats actually the way i'm going to go – iedoc Feb 23 '16 at 16:45
  • for what its worth, you could use this solution to generate your LUT :) – RyanP Feb 23 '16 at 16:46
  • i tagged c++ but should have tagged glsl. because it is a shader i'm actually programming, a lookup table would require me to upload it to the gpu. I will consider writing a lookup table right in the shader and do some testing to see which is actually faster, lookup table or this loop – iedoc Feb 23 '16 at 16:59
  • with the second piece of code you added, this is a type of solution i was looking for (the second piece of code runs faster than the loop) – iedoc Feb 23 '16 at 17:23
  • first presenting the loop and then unrolling it to detect up to 2 transitions also explains the resulting code very well. I'll upvote. – Maarten Hilferink Feb 23 '16 at 17:27
0

For your definition of uniform, the number has to be in the form 00011111 or 11110000. Consider the former one (zeros followed by ones).

Add one to the value. If it is uniform, it would have exactly one 1 bit, which means a power of 2.

To test whether a value is a power of two, use (x & (x - 1)) == 0. To shorten the code we don't need to add one in the previous step. Instead we check (x & (x + 1)) == 0

Apply this to the other case by NOT-ing the initial value and repeat the above process.

#include <cstdio>
bool isuniform(unsigned char x) {
  unsigned char y = ~x;
  return (x & (x + 1)) == 0 || (y & (y + 1)) == 0;
}
int main() {
  printf("%d\n", isuniform(0));   // 00000000
  printf("%d\n", isuniform(1));   // 00000001
  printf("%d\n", isuniform(3));   // 00000011
  printf("%d\n", isuniform(7));   // 00000111
  printf("%d\n", isuniform(15));  // 00001111
  printf("%d\n", isuniform(31));  // 00011111
  printf("%d\n", isuniform(63));  // 00111111
  printf("%d\n", isuniform(127)); // 01111111
  printf("%d\n", isuniform(255)); // 11111111
  printf("%d\n", isuniform(254)); // 11111110
  printf("%d\n", isuniform(252)); // 11111100
  printf("%d\n", isuniform(248)); // 11111000
  printf("%d\n", isuniform(240)); // 11110000
  printf("%d\n", isuniform(224)); // 11100000
  printf("%d\n", isuniform(192)); // 11000000
  printf("%d\n", isuniform(128)); // 10000000
  //----------
  printf("%d\n", isuniform(2));
  printf("%d\n", isuniform(4));
  printf("%d\n", isuniform(50));
  printf("%d\n", isuniform(123));
  printf("%d\n", isuniform(129));
  printf("%d\n", isuniform(253));
  return 0;
}
microtony
  • 192
  • 7
  • thanks for responding, but this only works if there is 1 transition or less (i'm looking for 2 or less). eg. 00000010 is not considered uniform with this answer. This is exactly what i would have been looking for if i wanted 1 or less transition though! – iedoc Feb 23 '16 at 17:19