@@ -17,103 +17,73 @@
17171818#include <time.h>
191920-/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
20+/* PCG Random Number Generation
21+ Based on the PCG family by Melissa O'Neill <oneill@pcg-random.org>
212222-To the extent possible under law, the author has dedicated all copyright
23-and related and neighboring rights to this software to the public domain
24-worldwide. This software is distributed without any warranty.
25-26-See <https://creativecommons.org/publicdomain/zero/1.0/>. */
27-28-/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
29- generators. It has excellent speed, a state size (128 bits) that is
30- large enough for mild parallelism, and it passes all tests we are aware
31- of.
32-33- For generating just single-precision (i.e., 32-bit) floating-point
34- numbers, xoshiro128+ is even faster.
35-36- The state must be seeded so that it is not everywhere zero. */
23+ This implements PCG-XSH-RR with 64-bit state and 32-bit output.
24+ On 32-bit platforms, uses an optimized 32-bit multiplier for better
25+ performance. On 64-bit platforms, uses the standard 64-bit multiplier
26+ for maximum statistical quality.
372728+ See <https://www.pcg-random.org/> for details. */
382930+/* Platform-adaptive multiplier selection:
31+ - 32-bit platforms: 0xf13283ad requires only 2 multiplies instead of 3
32+ - 64-bit platforms: standard multiplier for best statistical quality */
3933#ifdef MRB_32BIT
40-# define XORSHIFT96
41-# define NSEEDS 3
42-# define SEEDPOS 2
34+# define PCG_MULTIPLIER 0xf13283adULL
4335#else
44-# define NSEEDS 4
45-# define SEEDPOS 0
36+# define PCG_MULTIPLIER 6364136223846793005ULL
4637#endif
47-#define LASTSEED (NSEEDS-1)
38+#define PCG_INCREMENT 1442695040888963407ULL
48394940typedef struct rand_state {
50-uint32_t seed[NSEEDS];
41+uint64_t state;
42+uint32_t seed_value; /* Track last seed for srand compatibility */
5143} rand_state;
52445345static void
5446rand_init(rand_state *t)
5547{
56-t->seed[0] = 123456789;
57-t->seed[1] = 362436069;
58-t->seed[2] = 521288629;
59-#ifndef XORSHIFT96
60-t->seed[3] = 88675123;
61-#endif
48+t->state = 0x853c49e6748fea9bULL;
49+t->seed_value = 521288629;
6250}
63516452static uint32_t rand_uint32(rand_state *state);
65536654static uint32_t
6755rand_seed(rand_state *t, uint32_t seed)
6856{
69-uint32_t old_seed = t->seed[SEEDPOS];
70-rand_init(t);
71-t->seed[SEEDPOS] = seed;
57+uint32_t old_seed = t->seed_value;
58+59+/* PCG initialization: state=0, step, add seed, step, then mix */
60+t->state = 0;
61+rand_uint32(t);
62+t->state += seed;
7263for (int i = 0; i < 10; i++) {
7364rand_uint32(t);
7465 }
75-return old_seed;
76-}
776678-#ifndef XORSHIFT96
79-static inline uint32_t
80-rotl(const uint32_t x, int k) {
81-return (x << k) | (x >> (32 - k));
67+t->seed_value = seed;
68+return old_seed;
8269}
83-#endif
84708571static uint32_t
86-rand_uint32(rand_state *state)
72+rand_uint32(rand_state *rng)
8773{
88-#ifdef XORSHIFT96
89-uint32_t *seed = state->seed;
90-uint32_t x = seed[0];
91-uint32_t y = seed[1];
92-uint32_t z = seed[2];
93-uint32_t t = (x ^ (x << 3)) ^ (y ^ (y >> 19)) ^ (z ^ (z << 6));
94-95-x = y; y = z; z = t;
96-seed[0] = x;
97-seed[1] = y;
98-seed[2] = z;
99-100-return z;
101-#else
102-uint32_t *s = state->seed;
103-const uint32_t result = rotl(s[0] + s[3], 7) + s[0];
104-const uint32_t t = s[1] << 9;
74+/* PCG-XSH-RR: XorShift High (xorshift), then Random Rotate */
75+uint64_t oldstate = rng->state;
10576106-s[2] ^= s[0];
107-s[3] ^= s[1];
108-s[1] ^= s[2];
109-s[0] ^= s[3];
77+/* LCG step: advance internal state */
78+rng->state = oldstate * PCG_MULTIPLIER + PCG_INCREMENT;
11079111-s[2] ^= t;
112-s[3] = rotl(s[3], 11);
80+/* Output function: xorshift, then rotate by top bits */
81+uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);
82+uint32_t rot = (uint32_t)(oldstate >> 59u);
11383114-return result;
115-#endif /* XORSHIFT96 */
116- }
84+/* Rotate right by rot bits (handles rot=0 case correctly) */
85+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
86+}
1178711888#ifndef MRB_NO_FLOAT
11989static double