// 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
#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)
(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;
#endif
#ifdef FASTRAND_XOROSHIRO_ONLY_HIGHER
- result >>= 32;
+ result >>= 4;
#endif
return result;
}
#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)
#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;
// 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)
{
// 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;
}
t = t % bound;
while (l < t)
{
- r = fastrand_one(c);
+ r = fastrand_u32_helper(c);
m = (u64)r * bound;
l = (u32)m;
}
y |= y >> 8;
y |= y >> 16;
do
- r = fastrand_one(c) & y;
+ r = fastrand_u32_helper(c) & y;
while (r >= bound);
return r;
{
if ((intptr_t)p & 3)
{
- uint x = fastrand_one(c);
+ u32 x = fastrand_u32_helper(c);
while ((intptr_t)p & 3)
{
*p++ = x;
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;