Skip to content

Commit e6d5362

Browse files
committed
add PCG64
1 parent 9e7bbf6 commit e6d5362

File tree

11 files changed

+426
-24
lines changed

11 files changed

+426
-24
lines changed

ext/random/php_random.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
| Shawn Cokus <Cokus@math.washington.edu> |
2525
| David Blackman |
2626
| Sebastiano Vigna <vigna@acm.org> |
27+
| Melissa O'Neill <oneill@pcg-random.org> |
2728
+----------------------------------------------------------------------+
2829
*/
2930
#ifndef PHP_RANDOM_H
@@ -85,6 +86,62 @@
8586
# define php_random_int_silent(min, max, result) \
8687
php_random_int((min), (max), (result), 0)
8788

89+
# if !defined(__SIZEOF_INT128__) || defined(FORCE_EMULATE_128)
90+
# define RANDOM_PCG64_EMULATED
91+
typedef struct _random_uint128_t {
92+
uint64_t hi;
93+
uint64_t lo;
94+
} random_uint128_t;
95+
# define UINT128_HI64(value) value.hi;
96+
# define UINT128_LO64(value) value.lo;
97+
# define UINT128_CON(x, y, result) \
98+
do { \
99+
result.hi = x; \
100+
result.lo = y; \
101+
} while (0);
102+
# define UINT128_ADD(x, y, result) \
103+
do { \
104+
const uint64_t _lo = (x.lo + y.lo), _hi = (x.hi + y.hi + (_lo < x.lo)); \
105+
result.hi = _hi; \
106+
result.lo = _lo; \
107+
} while (0);
108+
# define UINT128_MUL(x, y, result) \
109+
do { \
110+
const uint64_t \
111+
_x0 = x.lo & 0xffffffffULL, \
112+
_x1 = x.lo >> 32, \
113+
_y0 = y.lo & 0xffffffffULL, \
114+
_y1 = y.lo >> 32, \
115+
_z0 = ((_x1 * _y0 + (_x0 * _y0 >> 32)) & 0xffffffffULL) + _x0 * _y1; \
116+
result.hi = x.hi * y.lo + x.lo * y.hi; \
117+
result.lo = x.lo * y.lo; \
118+
result.hi += _x1 * _y1 + ((_x1 * _y0 + (_x0 * _y0 >> 32)) >> 32) + (_z0 >> 32); \
119+
} while (0);
120+
# define PCG64_ROTL1OR1(x, result) \
121+
do { \
122+
result.hi = x.hi << 1U | x.lo >> 63U; \
123+
result.lo = x.lo << 1U | 1U; \
124+
} while (0);
125+
# define PCG64_ROTR64(x, result) \
126+
do { \
127+
const uint64_t _v = (x.hi ^ x.lo), _s = x.hi >> 58U; \
128+
result = (_v >> _s) | (_v << ((-_s) & 63)); \
129+
} while (0);
130+
# else
131+
typedef __uint128_t random_uint128_t;
132+
# define UINT128_HI64(value) (uint64_t) (value >> 64);
133+
# define UINT128_LO64(value) (uint64_t) value;
134+
# define UINT128_CON(x, y, result) result = (((random_uint128_t) x << 64) + y);
135+
# define UINT128_ADD(x, y, result) result = x + y;
136+
# define UINT128_MUL(x, y, result) result = x * y;
137+
# define PCG64_ROTL1OR1(x, result) result = (x << 1U) | 1U;
138+
# define PCG64_ROTR64(x, result) \
139+
do { \
140+
uint64_t _v = ((uint64_t) (x >> 64U)) ^ (uint64_t) x, _s = x >> 122U; \
141+
result = (_v >> _s) | (_v << ((-_s) & 63)); \
142+
} while (0);
143+
# endif
144+
88145
# define RANDOM_ENGINE_GENERATE(algo, state, result, generated_size, rng_unsafe) \
89146
do { \
90147
result = algo->generate(state, rng_unsafe); \
@@ -132,6 +189,7 @@ extern PHPAPI zend_class_entry *random_ce_Random_SeedableEngine;
132189
extern PHPAPI zend_class_entry *random_ce_Random_SerializableEngine;
133190

134191
extern PHPAPI zend_class_entry *random_ce_Random_Engine_CombinedLCG;
192+
extern PHPAPI zend_class_entry *random_ce_Random_Engine_PCG64;
135193
extern PHPAPI zend_class_entry *random_ce_Random_Engine_MersenneTwister;
136194
extern PHPAPI zend_class_entry *random_ce_Random_Engine_Secure;
137195
extern PHPAPI zend_class_entry *random_ce_Random_Engine_XorShift128Plus;
@@ -140,6 +198,7 @@ extern PHPAPI zend_class_entry *random_ce_Random_Randomizer;
140198

141199
extern const php_random_engine_algo php_random_engine_algo_combinedlcg;
142200
extern const php_random_engine_algo php_random_engine_algo_mersennetwister;
201+
extern const php_random_engine_algo php_random_engine_algo_pcg64;
143202
extern const php_random_engine_algo php_random_engine_algo_secure;
144203
extern const php_random_engine_algo php_random_engine_algo_user;
145204
extern const php_random_engine_algo php_random_engine_algo_xorshift128plus;
@@ -163,6 +222,11 @@ typedef struct _php_random_engine_state_mersennetwister {
163222
bool seeded;
164223
} php_random_engine_state_mersennetwister;
165224

225+
typedef struct _php_random_engine_state_pcg64 {
226+
random_uint128_t s;
227+
random_uint128_t inc;
228+
} php_random_engine_state_pcg64;
229+
166230
typedef struct _php_random_engine_state_user {
167231
zend_object *object;
168232
zend_function *generate_method;

0 commit comments

Comments
 (0)