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. --- CMakeLists.txt | 1 + random/CMakeLists.txt | 10 ++ random/LICENSE | 60 ++++++++++++ random/include/random/mt19937-64.h | 40 ++++++++ random/include/random/random.h | 3 + random/src/mt19937-64.c | 183 +++++++++++++++++++++++++++++++++++++ 6 files changed, 297 insertions(+) create mode 100644 random/CMakeLists.txt create mode 100644 random/LICENSE create mode 100644 random/include/random/mt19937-64.h create mode 100644 random/include/random/random.h create mode 100644 random/src/mt19937-64.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8eb368e..4695e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(list) add_subdirectory(listpool) add_subdirectory(log) add_subdirectory(mempool) +add_subdirectory(random) add_subdirectory(timer) diff --git a/random/CMakeLists.txt b/random/CMakeLists.txt new file mode 100644 index 0000000..ec80b1d --- /dev/null +++ b/random/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.0) + +project(random) + +add_library(random + src/mt19937-64.c) + +target_include_directories(random PUBLIC include) + +target_compile_options(random PRIVATE -Wall -Wextra) diff --git a/random/LICENSE b/random/LICENSE new file mode 100644 index 0000000..867af1f --- /dev/null +++ b/random/LICENSE @@ -0,0 +1,60 @@ +This library is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE. The +license text can be found in the top-level LICENSE file of this project. + +This library makes use of third-party software. The licenses for this +third-party software are listed below. + +# 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) diff --git a/random/include/random/mt19937-64.h b/random/include/random/mt19937-64.h new file mode 100644 index 0000000..bd1125f --- /dev/null +++ b/random/include/random/mt19937-64.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#define MT19937_64_NN 312 + +typedef struct mt19937_64 { + uint64_t mt[MT19937_64_NN]; // The array for the state vector. + int mti; // mti==NN+1 means mt[NN] is not initialized. +} mt19937_64; + +/// Creates a default-initialized 64-bit Mersenne Twister PRNG. +mt19937_64 mt19937_64_make(); + +/// Initializes the PRNG with a seed. +void mt19937_64_init(mt19937_64* rng, uint64_t seed); + +/// Initializes the PRNG with an array of values. +/// |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); + +/// Generates a random number in the [0, 2^64-1]-interval. +uint64_t mt19937_64_gen64u(mt19937_64* rng); + +/// Generates a random number in the [0, 2^63-1]-interval. +int64_t mt19937_64_gen64i(mt19937_64* rng); + +/// Generates a random number in the [0,1]-real-interval. +double mt19937_64_gen_real1(mt19937_64* rng); + +/// Generates a random number in the [0,1)-real-interval. +double mt19937_64_gen_real2(mt19937_64* rng); + +/// Generates a random number in the (0,1)-real-interval. +double mt19937_64_gen_real3(mt19937_64* rng); + +/// Generates a random number in the (-1,+1)-real-interval. +double mt19937_64_gen_real4(mt19937_64* rng); diff --git a/random/include/random/random.h b/random/include/random/random.h new file mode 100644 index 0000000..5499f62 --- /dev/null +++ b/random/include/random/random.h @@ -0,0 +1,3 @@ +#pragma once + +#include 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