#include #include #include static inline unsigned long statistical_prng() { static unsigned long statistical_prng_state = 2463534242U; unsigned long x = statistical_prng_state; if (sizeof(long) <= 4) { x ^= x << 13; x ^= x >> 17; x ^= x << 5; } else { x ^= x << 13; x ^= x >> 7; x ^= x << 17; } return statistical_prng_state = x; } /* returns the position of one bit set in , starting at position , and * searching in other halves if not found. This is intended to be used to * report the position of one bit set among several based on a counter or a * random generator while preserving a relatively good distribution so that * values made of holes in the middle do not see one of the bits around the * hole being returned much more often than the other one. It can be seen as a * disturbed ffsl() where the initial search starts at bit . The look up * is performed in O(logN) time for N bit words, yielding a bit among 64 in * about 16 cycles. Passing value 0 for makes no sense and -1 is returned * in this case. */ int one_among(unsigned long v, int bit) { /* note, these masks may be produced by ~0UL/((1UL< 4) ? 5 : 4; scale >= 0; scale--) { halfword >>= (1UL << scale); scope |= (1UL << scale); mirror = bit ^ (1UL << scale); if (v & ((1UL << bit) | (1UL << mirror))) return (v & (1UL << bit)) ? bit : mirror; if (!((v >> (bit & scope)) & halves[scale] & halfword)) bit = mirror; } return bit; } int main(int argc, char **argv) { unsigned long mask; int bit; if (argc < 2) { unsigned long long tests = 0; int ret; while (1) { mask = statistical_prng(); // note: cannot be zero bit = statistical_prng() % (sizeof(long) * 8); ret = one_among(mask, bit); if (ret < 0 || !((mask >> ret) & 1)) printf("###ERR### mask=%#lx bit=%d ret=%d\n", mask, bit, ret); if (!(tests & 0xffffff)) printf("count=%Ld mask=%lx bit=%d ret=%d\n", tests, mask, bit, ret); tests++; } } mask = atol(argv[1]); if (argc < 3) { for (bit = 0; bit < 8*sizeof(long); bit++) printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit)); } else { bit = atoi(argv[2]); printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit)); } return 0; }