From: Pavel Charvat Date: Tue, 9 Jun 2020 10:44:26 +0000 (+0200) Subject: Random: Use full 64bit output from xoroshiro128+, but prefer the higher bits. X-Git-Tag: v6.5.14~8 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=6ef53b3a12cf642a64deba64ea9f6f27c912e14b;p=libucw.git Random: Use full 64bit output from xoroshiro128+, but prefer the higher bits. --- diff --git a/ucw/random-fast.c b/ucw/random-fast.c index 9404abdc..5c8bfaab 100644 --- a/ucw/random-fast.c +++ b/ucw/random-fast.c @@ -75,11 +75,10 @@ // Scrambler: 1 (+), 2 (++), 3 (**) #define FASTRAND_XOROSHIRO_SCRAMBLER 1 -// If defined, we only use the highest 32 bits from each 64 bit number; -// useful especially for the weakest '+' scrambler. -// XXX: We could instead cut less bits or use full 64 bits and prefer -// the higher ones only where trivial, for example in 32 bit fastrand_max(). -#define FASTRAND_XOROSHIRO_ONLY_HIGHER +// If defined, we only use the highest 60 bits from each 64 bit number; +// useful especially for the weakest '+' scrambler. Even if not +// we prefer higher bits where trivial. +#undef FASTRAND_XOROSHIRO_ONLY_HIGHER /** * FASTRAND_USE_LIBC_SVID @@ -174,9 +173,10 @@ static inline u32 fastrand_one(struct fastrand *c) #ifdef FASTRAND_USE_XOROSHIRO #ifdef FASTRAND_XOROSHIRO_ONLY_HIGHER -# define FASTRAND_ONE_BITS 32 +# define FASTRAND_ONE_BITS 60 #else # define FASTRAND_ONE_BITS 64 +# define FASTRAND_PREFER_HIGHER #endif static void fastrand_init(struct fastrand *c) @@ -190,13 +190,7 @@ static void fastrand_init(struct fastrand *c) (uintmax_t)c->seed_value, FASTRAND_XOROSHIRO_SIZE, FASTRAND_XOROSHIRO_SCRAMBLER); } -static inline -#ifdef FASTRAND_XOROSHIRO_ONLY_HIGHER -u32 -#else -u64 -#endif -fastrand_one(struct fastrand *c) +static inline u64 fastrand_one(struct fastrand *c) { u64 result; u64 *s = c->xoroshiro_state; @@ -241,7 +235,7 @@ fastrand_one(struct fastrand *c) #endif #ifdef FASTRAND_XOROSHIRO_ONLY_HIGHER - result >>= 32; + result >>= 4; #endif return result; } @@ -361,10 +355,19 @@ COMPILE_ASSERT(fastrand_one_range, FASTRAND_ONE_BITS >= 32 && FASTRAND_ONE_BITS #define FASTRAND_ONE_MAX (UINT64_MAX >> (64 - FASTRAND_ONE_BITS)) #endif +static inline u32 fastrand_u32_helper(struct fastrand *c) +{ +#if FASTRAND_ONE_BITS > 32 && defined(FASTRAND_PREFER_HIGHER) + return fastrand_one(c) >> (FASTRAND_ONE_BITS - 32); +#else + return fastrand_one(c); +#endif +} + u32 fastrand_u32(struct fastrand *c) { FASTRAND_CHECK_SEED(c); - return fastrand_one(c); + return fastrand_u32_helper(c); } u64 fastrand_u64(struct fastrand *c) @@ -450,7 +453,7 @@ static inline u32 fastrand_max_u32_helper(struct fastrand *c, u32 bound) #if FASTRAND_MAX_U32_ALGORITHM == 1 while (1) { - u32 r = fastrand_one(c); + u32 r = fastrand_u32_helper(c); u32 x = r % bound; if (r - x <= (u32)-bound) return x; @@ -458,14 +461,14 @@ static inline u32 fastrand_max_u32_helper(struct fastrand *c, u32 bound) // Possible optimization for unlucky cases u32 y = r - x; do - r = fastrand_one(c); + r = fastrand_u32_helper(c); while (r >= y); return r % bound; #endif } #elif FASTRAND_MAX_U32_ALGORITHM == 2 - u32 r = fastrand_one(c); + u32 r = fastrand_u32_helper(c); u64 m = (u64)r * bound; u32 l = (u32)m; if (l < bound) @@ -477,7 +480,7 @@ static inline u32 fastrand_max_u32_helper(struct fastrand *c, u32 bound) { // Implies l < t % bound, so we don't need to check it before switching to completely different loop. do - r = fastrand_one(c); + r = fastrand_u32_helper(c); while (r >= bound); return r; } @@ -485,7 +488,7 @@ static inline u32 fastrand_max_u32_helper(struct fastrand *c, u32 bound) t = t % bound; while (l < t) { - r = fastrand_one(c); + r = fastrand_u32_helper(c); m = (u64)r * bound; l = (u32)m; } @@ -501,7 +504,7 @@ static inline u32 fastrand_max_u32_helper(struct fastrand *c, u32 bound) y |= y >> 8; y |= y >> 16; do - r = fastrand_one(c) & y; + r = fastrand_u32_helper(c) & y; while (r >= bound); return r; @@ -584,7 +587,7 @@ void fastrand_mem(struct fastrand *c, void *ptr, size_t size) { if ((intptr_t)p & 3) { - uint x = fastrand_one(c); + u32 x = fastrand_u32_helper(c); while ((intptr_t)p & 3) { *p++ = x; @@ -605,14 +608,14 @@ void fastrand_mem(struct fastrand *c, void *ptr, size_t size) for (size_t n = size >> 2; n--; ) #endif { - *(u32 *)p = fastrand_one(c); + *(u32 *)p = fastrand_u32_helper(c); p += 4; } size &= 3; } if (size) { - uint x = fastrand_one(c); + u32 x = fastrand_u32_helper(c); while (size--) { *p++ = x;