/* Purpose: a simple random number generator -BEN- */
+#if defined(WINDOWS)
+#include <Windows.h>
+#endif
+
#include "z-rand.h"
};
+typedef struct {
+ u32b dw[2];
+} u64b;
+
+static u64b u64b_xor(u64b a, u64b b)
+{
+ u64b result;
+
+ result.dw[0] = a.dw[0] ^ b.dw[0];
+ result.dw[1] = a.dw[1] ^ b.dw[1];
+
+ return result;
+}
+
+static u64b u64b_shiftl(u64b x, int k)
+{
+ u64b result;
+
+ if (k < 32) {
+ result.dw[1] = (x.dw[1] << k) | (x.dw[0] >> (32 - k));
+ result.dw[0] = (x.dw[0] << k);
+ }
+ else {
+ result.dw[1] = (x.dw[0] << (k - 32));
+ result.dw[0] = 0;
+ }
+
+ return result;
+}
+
+static u64b u64b_rotl(u64b x, int k)
+{
+ u64b result;
+
+ if (k < 32) {
+ result.dw[0] = (x.dw[0] << k) | (x.dw[1] >> (32 - k));
+ result.dw[1] = (x.dw[1] << k) | (x.dw[0] >> (32 - k));
+ }
+ else {
+ result.dw[0] = (x.dw[0] >> (64 - k)) | (x.dw[1] << (k - 32));
+ result.dw[1] = (x.dw[1] >> (64 - k)) | (x.dw[0] << (k - 32));
+ }
+
+ return result;
+}
+
+static u64b u64b_add(u64b a, u64b b)
+{
+ u64b result;
+
+ result.dw[0] = a.dw[0] + b.dw[0];
+ result.dw[1] = a.dw[1] + b.dw[1];
+
+ if (result.dw[0] < a.dw[0])
+ result.dw[1] ++;
+
+ return result;
+}
+
/*
* Initialize Xorshift Algorithm state
*/
-static void Rand_Xorshift_init(u32b seed, u32b* state)
+static void Rand_Xorshift_seed(u32b seed, u32b* state)
{
int i;
}
}
+#if 0
/*
* Xorshift Algorithm
*/
return state[3];
}
+#endif
+
+/*
+ * Xoroshiro128+ Algorithm
+ */
+static u32b Rand_Xoroshiro128plus(u32b* state)
+{
+ const u64b s0 = *((u64b*)state);
+ u64b s1 = *((u64b*)state + 1);
+ const u64b result = u64b_add(s0, s1);
+
+ s1 = u64b_xor(s0, s1);
+ *((u64b*)state) = u64b_xor(u64b_xor(u64b_rotl(s0, 55), s1), u64b_shiftl(s1, 14));
+ *((u64b*)state + 1) = u64b_rotl(s1, 36);
+
+ return result.dw[0];
+}
+
+static const u32b Rand_Xorshift_max = 0xFFFFFFFF;
/*
* Initialize the RNG using a new seed
*/
-void Rand_state_init(u32b seed)
+void Rand_state_set(u32b seed)
+{
+ Rand_Xorshift_seed(seed, Rand_state);
+}
+
+void Rand_state_init(void)
{
- Rand_Xorshift_init(seed, Rand_state);
+#ifdef RNG_DEVICE
+
+ FILE *fp = fopen(RNG_DEVICE, "r");
+
+ do {
+ fread(Rand_state, sizeof(Rand_state[0]), 4, fp);
+ } while ((Rand_state[0] | Rand_state[1] | Rand_state[2] | Rand_state[3]) == 0);
+
+ fclose(fp);
+
+#elif defined(WINDOWS)
+
+ HCRYPTPROV hProvider;
+
+ CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, 0);
+
+ do {
+ CryptGenRandom(hProvider, sizeof(Rand_state[0]) * 4, (BYTE*)Rand_state);
+ } while ((Rand_state[0] | Rand_state[1] | Rand_state[2] | Rand_state[3]) == 0);
+
+ CryptReleaseContext(hProvider, 0);
+
+#else
+
+ /* Basic seed */
+ u32b seed = (time(NULL));
+#ifdef SET_UID
+ /* Mutate the seed on Unix machines */
+ seed = ((seed >> 3) * (getpid() << 1));
+#endif
+ /* Seed the RNG */
+ Rand_state_set(seed);
+
+#endif
}
/*
/*
* Extract a "random" number from 0 to m-1, via "division"
*/
-s32b Rand_div(u32b m)
+static s32b Rand_div_impl(s32b m, u32b* state)
{
+ u32b scaling;
+ u32b past;
+ u32b ret;
+
/* Hack -- simple case */
if (m <= 1) return (0);
- /* Use the value */
- return Rand_Xorshift(Rand_state) % m;
+ scaling = Rand_Xorshift_max / m;
+ past = scaling * m;
+
+ do {
+ ret = Rand_Xoroshiro128plus(state);
+ } while (ret >= past);
+
+ return ret / scaling;
+}
+
+s32b Rand_div(s32b m)
+{
+ return Rand_div_impl(m, Rand_state);
}
s16b high = RANDNOR_NUM;
/* Paranoia */
- if (stand < 1) return (mean);
+ if (stand < 1) return (s16b)(mean);
/* Roll for probability */
tmp = (s16b)randint0(32768);
/* Move left otherwise */
else
{
- high = mid;
+ high = (s16b)mid;
}
}
{
int i, sum = 0;
for (i = 0; i < num; i++) sum += randint1(sides);
- return (sum);
+ return (s16b)(sum);
}
*
* Could also use rand() from <stdlib.h> directly. XXX XXX XXX
*/
-u32b Rand_external(u32b m)
+s32b Rand_external(s32b m)
{
static bool initialized = FALSE;
static u32b Rand_state_external[4];
if (!initialized)
{
/* Initialize with new seed */
- u32b seed = time(NULL);
- Rand_Xorshift_init(seed, Rand_state_external);
+ u32b seed = (u32b)time(NULL);
+ Rand_Xorshift_seed(seed, Rand_state_external);
initialized = TRUE;
}
- return Rand_Xorshift(Rand_state_external) % m;
+ return Rand_div_impl(m, Rand_state_external);
}