mirror of
				https://git.haproxy.org/git/haproxy.git/
				synced 2025-10-31 16:41:01 +01:00 
			
		
		
		
	This one produces random numbers and verifies that the output is correct. It can also take arguments to test individual values.
		
			
				
	
	
		
			106 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdint.h>
 | |
| 
 | |
| 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 <v>, starting at position <bit>, 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 <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 <v> 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<<scale)+1) but
 | |
| 	 * that's more expensive.
 | |
| 	 */
 | |
| 	static const unsigned long halves[] = {
 | |
| 		(unsigned long)0x5555555555555555ULL,
 | |
| 		(unsigned long)0x3333333333333333ULL,
 | |
| 		(unsigned long)0x0F0F0F0F0F0F0F0FULL,
 | |
| 		(unsigned long)0x00FF00FF00FF00FFULL,
 | |
| 		(unsigned long)0x0000FFFF0000FFFFULL,
 | |
| 		(unsigned long)0x00000000FFFFFFFFULL
 | |
| 	};
 | |
| 	unsigned long halfword = ~0UL;
 | |
| 	int scope = 0;
 | |
| 	int mirror;
 | |
| 	int scale;
 | |
| 
 | |
| 	if (!v)
 | |
| 		return -1;
 | |
| 
 | |
| 	/* we check if the exact bit is set or if it's present in a mirror
 | |
| 	 * position based on the current scale we're checking, in which case
 | |
| 	 * it's returned with its current (or mirrored) value. Otherwise we'll
 | |
| 	 * make sure there's at least one bit in the half we're in, and will
 | |
| 	 * scale down to a smaller scope and try again, until we find the
 | |
| 	 * closest bit.
 | |
| 	 */
 | |
| 	for (scale = (sizeof(long) > 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;
 | |
| }
 |