From 344960f7470d7b6e5cb0c0b1d7e751d47063a98c Mon Sep 17 00:00:00 2001 From: Marc Sunet Date: Sat, 7 May 2022 08:09:10 -0700 Subject: Add random library. --- random/src/mt19937-64.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 random/src/mt19937-64.c (limited to 'random/src/mt19937-64.c') diff --git a/random/src/mt19937-64.c b/random/src/mt19937-64.c new file mode 100644 index 0000000..b6f7be6 --- /dev/null +++ b/random/src/mt19937-64.c @@ -0,0 +1,183 @@ +// http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/VERSIONS/C-LANG/mt19937-64.c + +/* + A C-program for MT19937-64 (2004/9/29 version). + Coded by Takuji Nishimura and Makoto Matsumoto. + + This is a 64-bit version of Mersenne Twister pseudorandom number + generator. + + Before using, initialize the state by using init_genrand64(seed) + or init_by_array64(init_key, key_length). + + Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + References: + T. Nishimura, ``Tables of 64-bit Mersenne Twisters'' + ACM Transactions on Modeling and + Computer Simulation 10. (2000) 348--357. + M. Matsumoto and T. Nishimura, + ``Mersenne Twister: a 623-dimensionally equidistributed + uniform pseudorandom number generator'' + ACM Transactions on Modeling and + Computer Simulation 8. (Jan. 1998) 3--30. + + Any feedback is very welcome. + http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces) +*/ + +/* +Modifications: + +- Remove stdio.h and the main() function. +- Replace 'unsigned long long' with 'uint64_t' (include stdint.h). +- Remove the global state and instead store the generator's state in the new + mt19937_64 struct. +- Naming and formatting. +*/ + +#include + +#include + +#define NN 312 +#define MM 156 +#define MATRIX_A 0xB5026F5AA96619E9ULL +#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */ +#define LM 0x7FFFFFFFULL /* Least significant 31 bits */ + +mt19937_64 mt19937_64_make() { + mt19937_64 rng; + rng.mti = NN+1; // Not initialized. + return rng; +} + +/* initializes mt[NN] with a seed */ +void mt19937_64_init(mt19937_64* rng, uint64_t seed) { + assert(rng); + rng->mt[0] = seed; + for (rng->mti = 1; rng->mti < NN; rng->mti++) { + rng->mt[rng->mti] = + (6364136223846793005ULL * (rng->mt[rng->mti - 1] ^ (rng->mt[rng->mti - 1] >> 62)) + rng->mti); + } +} + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +void mt19937_64_init_by_array64(mt19937_64* rng, uint64_t init_key[], uint64_t key_length) { + assert(rng); + uint64_t i, j, k; + mt19937_64_init(rng, 19650218ULL); + i=1; j=0; + k = (NN>key_length ? NN : key_length); + for (; k; k--) { + rng->mt[i] = (rng->mt[i] ^ ((rng->mt[i-1] ^ (rng->mt[i-1] >> 62)) * 3935559000370003845ULL)) + + init_key[j] + j; /* non linear */ + i++; j++; + if (i>=NN) { rng->mt[0] = rng->mt[NN-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=NN-1; k; k--) { + rng->mt[i] = (rng->mt[i] ^ ((rng->mt[i-1] ^ (rng->mt[i-1] >> 62)) * 2862933555777941757ULL)) + - i; /* non linear */ + i++; + if (i>=NN) { rng->mt[0] = rng->mt[NN-1]; i=1; } + } + + rng->mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */ +} + +/* generates a random number on [0, 2^64-1]-interval */ +uint64_t mt19937_64_gen64u(mt19937_64* rng) { + assert(rng); + int i; + uint64_t x; + static uint64_t mag01[2]={0ULL, MATRIX_A}; + + if (rng->mti >= NN) { /* generate NN words at one time */ + + /* if mt19937_64_init() has not been called, */ + /* a default initial seed is used */ + if (rng->mti == NN+1) + mt19937_64_init(rng, 5489ULL); + + for (i=0;imt[i]&UM)|(rng->mt[i+1]&LM); + rng->mt[i] = rng->mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; + } + for (;imt[i]&UM)|(rng->mt[i+1]&LM); + rng->mt[i] = rng->mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; + } + x = (rng->mt[NN-1]&UM)|(rng->mt[0]&LM); + rng->mt[NN-1] = rng->mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; + + rng->mti = 0; + } + + x = rng->mt[rng->mti++]; + + x ^= (x >> 29) & 0x5555555555555555ULL; + x ^= (x << 17) & 0x71D67FFFEDA60000ULL; + x ^= (x << 37) & 0xFFF7EEE000000000ULL; + x ^= (x >> 43); + + return x; +} + +/* generates a random number on [0, 2^63-1]-interval */ +int64_t mt19937_64_gen64i(mt19937_64* rng) { + return (int64_t)(mt19937_64_gen64u(rng) >> 1); +} + +/* generates a random number on [0,1]-real-interval */ +double mt19937_64_gen_real1(mt19937_64* rng) { + return (mt19937_64_gen64u(rng) >> 11) * (1.0/9007199254740991.0); +} + +/* generates a random number on [0,1)-real-interval */ +double mt19937_64_gen_real2(mt19937_64* rng) { + return (mt19937_64_gen64u(rng) >> 11) * (1.0/9007199254740992.0); +} + +/* generates a random number on (0,1)-real-interval */ +double mt19937_64_gen_real3(mt19937_64* rng) { + return ((mt19937_64_gen64u(rng) >> 12) + 0.5) * (1.0/4503599627370496.0); +} + +/* generates a random number on (-1,+1)-real-interval */ +double mt19937_64_gen_real4(mt19937_64* rng) { + const double x01 = mt19937_64_gen_real3(rng); // (0,1) interval. + const double x11 = x01 * 2. - 1.; // (-1, +1) interval. + return x11; +} -- cgit v1.2.3