blob: bd1919298529d7d43a1756e953c3826efc45806e [file] [log] [blame]
Willy Tarreau798d6fc2022-06-21 20:28:14 +02001#include <stdio.h>
2#include <stdlib.h>
3#include <stdint.h>
4
5static inline unsigned long statistical_prng()
6{
7 static unsigned long statistical_prng_state = 2463534242U;
8 unsigned long x = statistical_prng_state;
9
10 if (sizeof(long) <= 4) {
11 x ^= x << 13;
12 x ^= x >> 17;
13 x ^= x << 5;
14 } else {
15 x ^= x << 13;
16 x ^= x >> 7;
17 x ^= x << 17;
18 }
19 return statistical_prng_state = x;
20}
21
22/* returns the position of one bit set in <v>, starting at position <bit>, and
23 * searching in other halves if not found. This is intended to be used to
24 * report the position of one bit set among several based on a counter or a
25 * random generator while preserving a relatively good distribution so that
26 * values made of holes in the middle do not see one of the bits around the
27 * hole being returned much more often than the other one. It can be seen as a
28 * disturbed ffsl() where the initial search starts at bit <bit>. The look up
29 * is performed in O(logN) time for N bit words, yielding a bit among 64 in
30 * about 16 cycles. Passing value 0 for <v> makes no sense and -1 is returned
31 * in this case.
32 */
33int one_among(unsigned long v, int bit)
34{
35 /* note, these masks may be produced by ~0UL/((1UL<<scale)+1) but
36 * that's more expensive.
37 */
38 static const unsigned long halves[] = {
39 (unsigned long)0x5555555555555555ULL,
40 (unsigned long)0x3333333333333333ULL,
41 (unsigned long)0x0F0F0F0F0F0F0F0FULL,
42 (unsigned long)0x00FF00FF00FF00FFULL,
43 (unsigned long)0x0000FFFF0000FFFFULL,
44 (unsigned long)0x00000000FFFFFFFFULL
45 };
46 unsigned long halfword = ~0UL;
47 int scope = 0;
48 int mirror;
49 int scale;
50
51 if (!v)
52 return -1;
53
54 /* we check if the exact bit is set or if it's present in a mirror
55 * position based on the current scale we're checking, in which case
56 * it's returned with its current (or mirrored) value. Otherwise we'll
57 * make sure there's at least one bit in the half we're in, and will
58 * scale down to a smaller scope and try again, until we find the
59 * closest bit.
60 */
61 for (scale = (sizeof(long) > 4) ? 5 : 4; scale >= 0; scale--) {
62 halfword >>= (1UL << scale);
63 scope |= (1UL << scale);
64 mirror = bit ^ (1UL << scale);
65 if (v & ((1UL << bit) | (1UL << mirror)))
66 return (v & (1UL << bit)) ? bit : mirror;
67
68 if (!((v >> (bit & scope)) & halves[scale] & halfword))
69 bit = mirror;
70 }
71 return bit;
72}
73
74int main(int argc, char **argv)
75{
76 unsigned long mask;
77 int bit;
78
79 if (argc < 2) {
80 unsigned long long tests = 0;
81 int ret;
82
83 while (1) {
84 mask = statistical_prng(); // note: cannot be zero
85 bit = statistical_prng() % (sizeof(long) * 8);
86 ret = one_among(mask, bit);
87 if (ret < 0 || !((mask >> ret) & 1))
88 printf("###ERR### mask=%#lx bit=%d ret=%d\n", mask, bit, ret);
89 if (!(tests & 0xffffff))
90 printf("count=%Ld mask=%lx bit=%d ret=%d\n", tests, mask, bit, ret);
91 tests++;
92 }
93 }
94
95 mask = atol(argv[1]);
96
97 if (argc < 3) {
98 for (bit = 0; bit < 8*sizeof(long); bit++)
99 printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit));
100 } else {
101 bit = atoi(argv[2]);
102 printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit));
103 }
104 return 0;
105}