Ignore:
Timestamp:
Mar 21, 2023, 7:44:45 AM (19 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, ast-experimental, master
Children:
1205b3e
Parents:
12b006c
Message:

use splitmix32/64 to prime set seed for all PRNG

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/bits/random.hfa

    r12b006c r90fb672  
    1010// Created On       : Fri Jan 14 07:18:11 2022
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 20 10:01:40 2023
    13 // Update Count     : 180
     12// Last Modified On : Mon Mar 20 21:45:24 2023
     13// Update Count     : 186
    1414//
    1515
     
    131131#ifdef __cforall                                                                                // don't include in C code (invoke.h)
    132132
    133 // Splitmix64
    134133// https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
    135 // Splitmix64 is not recommended for demanding random number requirements,
    136 // but is often used to calculate initial states for other more complex
    137 // pseudo-random number generators.                             
     134//
     135// Splitmix64 is not recommended for demanding random number requirements, but is often used to calculate initial states
     136// for other more complex pseudo-random number generators (see https://prng.di.unimi.it).
     137// Also https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64.
    138138static inline uint64_t splitmix64( uint64_t & state ) {
    139139    state += 0x9e3779b97f4a7c15;
     
    149149} // splitmix64_set_seed
    150150
    151 // Splitmix32
    152151// https://github.com/bryc/code/blob/master/jshash/PRNGs.md#splitmix32
    153 // Splitmix32 is not recommended for demanding random number requirements,
    154 // but is often used to calculate initial states for other more complex
    155 // pseudo-random number generators.
    156 // SplitMix32 is a 32 bit variant of Splitmix64
     152//
     153// Splitmix32 is not recommended for demanding random number requirements, but is often used to calculate initial states
     154// for other more complex pseudo-random number generators (see https://prng.di.unimi.it).
     155
    157156static inline uint32_t splitmix32( uint32_t & state ) {
    158157    state += 0x9e3779b9;
     
    169168
    170169#ifdef __SIZEOF_INT128__
    171         //--------------------------------------------------
    172         static inline uint64_t lehmer64( __uint128_t & state ) {
    173                 __uint128_t ret = state;
    174                 state *= 0x_da94_2042_e4dd_58b5;
    175                 return ret >> 64;
    176         } // lehmer64
    177 
    178         static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {
    179                 // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed.
    180                 state = seed;
    181                 lehmer64( state );                                                              // prime
    182         } // lehmer64_set_seed
    183 
    184         //--------------------------------------------------
    185         static inline uint64_t wyhash64( uint64_t & state ) {
    186                 uint64_t ret = state;
    187                 state += 0x_60be_e2be_e120_fc15;
    188                 __uint128_t tmp;
    189                 tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;
    190                 uint64_t m1 = (tmp >> 64) ^ tmp;
    191                 tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;
    192                 uint64_t m2 = (tmp >> 64) ^ tmp;
    193                 return m2;
    194         } // wyhash64
     170//--------------------------------------------------
     171static inline uint64_t lehmer64( __uint128_t & state ) {
     172        __uint128_t ret = state;
     173        state *= 0x_da94_2042_e4dd_58b5;
     174        return ret >> 64;
     175} // lehmer64
     176
     177static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {
     178        // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed.
     179        state = splitmix64( seed );                                                     // prime
     180} // lehmer64_set_seed
     181
     182//--------------------------------------------------
     183static inline uint64_t wyhash64( uint64_t & state ) {
     184        uint64_t ret = state;
     185        state += 0x_60be_e2be_e120_fc15;
     186        __uint128_t tmp;
     187        tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;
     188        uint64_t m1 = (tmp >> 64) ^ tmp;
     189        tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;
     190        uint64_t m2 = (tmp >> 64) ^ tmp;
     191        return m2;
     192} // wyhash64
     193
     194static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {
     195        state = splitmix64( seed );                                                     // prime
     196} // wyhash64_set_seed
    195197#endif // __SIZEOF_INT128__
    196198
     
    227229
    228230static inline void xoshiro256pp_set_seed( xoshiro256pp_t & state, uint64_t seed ) {
    229     // these are done explicitly in this order to attain repeatable seeding.
    230     // do not call splitmix64 directly in the state init since order of argument evaluation
    231     // may not be consistent leading to irreproducible seeding
    232     uint64_t seed1 = splitmix64( seed );
     231    // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
     232    uint64_t seed1 = splitmix64( seed );                                // prime
    233233    uint64_t seed2 = splitmix64( seed );
    234234    uint64_t seed3 = splitmix64( seed );
    235235    uint64_t seed4 = splitmix64( seed );
    236236        state = (xoshiro256pp_t){ seed1, seed2, seed3, seed4 };
    237         xoshiro256pp( state );                                                          // prime
    238237} // xoshiro256pp_set_seed
    239238
     
    269268
    270269static inline void xoshiro128pp_set_seed( xoshiro128pp_t & state, uint32_t seed ) {
    271     // these are done explicitly in this order to attain repeatable seeding.
    272     // do not call splitmix32 directly in the state init since order of argument evaluation
    273     // may not be consistent leading to irreproducible seeding
    274     uint32_t seed1 = splitmix32( seed );
     270    // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
     271    uint32_t seed1 = splitmix32( seed );                                // prime
    275272    uint32_t seed2 = splitmix32( seed );
    276273    uint32_t seed3 = splitmix32( seed );
    277274    uint32_t seed4 = splitmix32( seed );
    278275        state = (xoshiro128pp_t){ seed1, seed2, seed3, seed4 };
    279         xoshiro128pp( state );                                                          // prime
    280276} // xoshiro128pp_set_seed
    281277
     
    290286
    291287static inline void xorshift_13_7_17_set_seed( uint64_t & state, uint64_t seed ) {
    292         state = seed;
    293         xorshift_13_7_17( state );                                                      // prime
     288        state = splitmix64( seed );                                                     // prime
    294289} // xorshift_13_7_17_set_seed
    295290
     
    308303
    309304static inline void xorshift_6_21_7_set_seed( uint32_t & state, uint32_t seed ) {
    310         state = seed;
    311         xorshift_6_21_7( state );                                                       // prime
     305    state = splitmix32( seed );                                                 // prime
    312306} // xorshift_6_21_7_set_seed
    313307
     
    323317
    324318static inline void xorshift_12_25_27_set_seed( uint64_t & state, uint64_t seed ) {
    325         state = seed;
    326         xorshift_12_25_27( state );                                                     // prime
     319        state = splitmix64( seed );                                                     // prime
    327320} // xorshift_12_25_27_set_seed
    328321
     
    345338
    346339static inline void kiss_64_set_seed( kiss_64_t & rs, uint64_t seed ) with(rs) {
    347         z = 1; w = 1; jsr = 4; jcong = seed;
    348         kiss_64( rs );                                                                          // prime
     340        z = 1; w = 1; jsr = 4; jcong = splitmix64( seed );      // prime
    349341} // kiss_64_set_seed
    350342
     
    374366
    375367static inline void xorwow_set_seed( xorwow_t & rs, uint32_t seed ) {
    376     // these are done explicitly in this order to attain repeatable seeding.
    377     // do not call splitmix32 directly in the state init since order of argument evaluation
    378     // may not be consistent leading to irreproducible seeding
    379     uint32_t seed1 = splitmix32( seed );
     368    // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined.
     369    uint32_t seed1 = splitmix32( seed );                                // prime
    380370    uint32_t seed2 = splitmix32( seed );
    381371    uint32_t seed3 = splitmix32( seed );
    382372    uint32_t seed4 = splitmix32( seed );
    383373        rs = (xorwow_t){ seed1, seed2, seed3, seed4, 0 };
    384         xorwow( rs );                                                                           // prime
    385374} // xorwow_set_seed
    386375
     
    388377// Used in __tls_rand_fwd
    389378#define M  (1_l64u << 48_l64u)
    390 #define A  (25214903917_l64u)
    391 #define AI (18446708753438544741_l64u)
     379#define A  (25_214_903_917_l64u)
     380#define AI (18_446_708_753_438_544_741_l64u)
    392381#define C  (11_l64u)
    393382#define D  (16_l64u)
Note: See TracChangeset for help on using the changeset viewer.