GitHub

@@ -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

48394940

typedef 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;

52445345

static void

5446

rand_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

}

63516452

static uint32_t rand_uint32(rand_state *state);

65536654

static uint32_t

6755

rand_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;

7263

for (int i = 0; i < 10; i++) {

7364

rand_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

84708571

static 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

11989

static double

Read the original on github.com ↗