main.c (25696B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * 19 * ## Notice 20 * 21 * The original C code and copyright notice are from the [source implementation]{@link http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c}. The implementation has been modified according to the styles and conventions of this project. 22 * 23 * ```text 24 * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, 25 * All rights reserved. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 31 * 1. Redistributions of source code must retain the above copyright 32 * notice, this list of conditions and the following disclaimer. 33 * 34 * 2. Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in the 36 * documentation and/or other materials provided with the distribution. 37 * 38 * 3. The names of its contributors may not be used to endorse or promote 39 * products derived from this software without specific prior written 40 * permission. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 46 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 47 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 48 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 49 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 50 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 51 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 52 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 * ``` 54 */ 55 56 // Note: keep project includes in alphabetical order... 57 #include <stdlib.h> 58 #include <stdint.h> 59 #include <string.h> 60 #include "stdlib/random/base.h" 61 #include "stdlib/random/base/mt19937.h" 62 63 // Forward declarations: 64 static inline int8_t next( struct BasePRNGObject *obj, uint64_t *out ); 65 static inline int8_t normalized( struct BasePRNGObject *obj, double *out ); 66 static inline void mt19937_free( struct BasePRNGObject *obj ); 67 68 static inline void create_state( uint32_t *state, const int32_t N, const uint32_t s ); 69 static inline void init_state( uint32_t *state, const int32_t N, const uint32_t *seed, const int64_t M ); 70 static inline void twist( uint32_t *state, const int32_t N ); 71 72 // Define the size of the state array (see refs): 73 static const int32_t N = 624; 74 75 // Define a (magic) constant used for indexing into the state array: 76 static const int32_t M = 397; 77 78 // Define an initial state (magic) constant: 19650218 => 00000001001010111101011010101010 79 static const uint32_t SEED_ARRAY_INIT_STATE = 19650218; 80 81 // Define a mask for the most significant `w-r` bits, where `w` is the word size (32 bits) and `r` is the separation point of one word (see refs): 2147483648 => 0x80000000 => 10000000000000000000000000000000 82 static const uint32_t UPPER_MASK = 0x80000000; 83 84 // Define a mask for the least significant `r` bits (see refs): 2147483647 => 0x7fffffff => 01111111111111111111111111111111 85 static const uint32_t LOWER_MASK = 0x7fffffff; 86 87 // Define a multiplier (see Knuth TAOCP Vol2. 3rd Ed. P.106): 1812433253 => 01101100000001111000100101100101 88 static const uint32_t KNUTH_MULTIPLIER = 1812433253; 89 90 // Define a (magic) multiplier: 1664525 => 00000000000110010110011000001101 91 static const uint32_t MAGIC_MULTIPLIER_1 = 1664525; 92 93 // Define a (magic) multiplier: 1566083941 => 01011101010110001000101101100101 94 static const uint32_t MAGIC_MULTIPLIER_2 = 1566083941; 95 96 // Define a tempering coefficient: 2636928640 => 0x9d2c5680 => 10011101001011000101011010000000 97 static const uint32_t TEMPERING_COEFFICIENT_1 = 0x9d2c5680; 98 99 // Define a tempering coefficient: 4022730752 => 0xefc60000 => 11101111110001100000000000000000 100 static const uint32_t TEMPERING_COEFFICIENT_2 = 0xefc60000; 101 102 // Define a constant vector `a` (see refs): 2567483615 => 0x9908b0df => 10011001000010001011000011011111 103 static const uint32_t MATRIX_A = 0x9908b0df; 104 105 // MAG01[x] = x * MATRIX_A; for x = {0,1} 106 static const uint32_t MAG01[2] = { 0x0, MATRIX_A }; 107 108 // Define the maximum unsigned 32-bit integer: 4294967295 => 11111111111111111111111111111111 109 static const uint32_t MAX_UINT32 = 4294967295; 110 111 // Define the maximum "safe" double-precision floating-point integer: 112 static const double FLOAT64_MAX_SAFE_INTEGER = 9007199254740991.0; 113 114 // Define a normalization constant when generating double-precision floating-point numbers: 2^53 => 9007199254740992 115 static const double FLOAT64_NORMALIZATION_CONSTANT = 1.0 / ( FLOAT64_MAX_SAFE_INTEGER+1.0 ); 116 117 // 2^26: 67108864 118 static const double TWO_26 = 67108864.0; 119 120 // 2^32: 2147483648 => 0x80000000 => 10000000000000000000000000000000 121 static const uint32_t TWO_32 = 0x80000000; 122 123 // 1 (as a 32-bit unsigned integer): 1 => 0x1 => 00000000000000000000000000000001 124 static const uint32_t ONE = 0x1; 125 126 // Define the maximum normalized pseudorandom double-precision floating-point number: ( (((2^32-1)>>>5)*2^26)+( (2^32-1)>>>6) ) / 2^53 127 static const double MAX_NORMALIZED = FLOAT64_MAX_SAFE_INTEGER * FLOAT64_NORMALIZATION_CONSTANT; 128 129 /** 130 * MT19937 PRNG. 131 * 132 * @private 133 */ 134 static const struct BasePRNG mt19937_prng = { 135 "mt19937", // name 136 (uint64_t)1, // min 137 (uint64_t)MAX_UINT32, // max: (2^{32}-1) 138 0.0, // min (normalized) 139 MAX_NORMALIZED, // max (normalized): (2^{53}-1)/2^{53} 140 sizeof( stdlib_base_random_mt19937_state_t ), // state_size 141 &next, // next() 142 &normalized, // normalized() 143 &mt19937_free // free() 144 }; 145 146 /** 147 * Returns a pseudorandom integer. 148 * 149 * ## Notes 150 * 151 * - The function returns `-1` if unable to generate a pseudorandom integer and `0` otherwise. 152 * 153 * ## References 154 * 155 * - Matsumoto, Makoto, and Takuji Nishimura. 1998. "Mersenne Twister: A 623-dimensionally Equidistributed Uniform Pseudo-random Number Generator." _ACM Transactions on Modeling and Computer Simulation_ 8 (1). New York, NY, USA: ACM: 3–30. doi:[10.1145/272991.272995][@matsumoto:1998a]. 156 * 157 * @private 158 * @param obj PRNG object 159 * @param out output address 160 * @return status code 161 */ 162 static inline int8_t next( struct BasePRNGObject *obj, uint64_t *out ) { 163 stdlib_base_random_mt19937_state_t *so; 164 uint32_t *state; 165 uint32_t r; 166 int32_t i; 167 if ( obj == NULL || obj->prng != &mt19937_prng ) { 168 return -1; 169 } 170 // Retrieve the state object: 171 so = (stdlib_base_random_mt19937_state_t *)( obj->state ); 172 173 // Retrieve the current state and current state index: 174 state = so->state; 175 i = so->i; 176 177 // Determine if we need to update our internal state array: 178 if ( i >= N ) { 179 twist( so->state, N ); 180 i = 0; 181 } 182 // Get the next state value: 183 r = so->state[ i ]; 184 185 // Update the state index: 186 so->i = i + 1; 187 188 // Tempering transform to compensate for the reduced dimensionality of equidistribution: 189 r ^= r >> 11; 190 r ^= ( r << 7 ) & TEMPERING_COEFFICIENT_1; 191 r ^= ( r << 15 ) & TEMPERING_COEFFICIENT_2; 192 r ^= r >> 18; 193 194 // Set the output value: 195 *out = (uint64_t)( r ); 196 197 return 0; 198 } 199 200 /** 201 * Returns a pseudorandom double-precision floating-point number on the interval `[0,1)`. 202 * 203 * ## Method 204 * 205 * - When generating normalized double-precision floating-point numbers, we first generate two pseudorandom integers \\( x \\) and \\( y \\) on the interval \\( [1,2^{32}-1) \\) for a combined \\( 64 \\) random bits. 206 * 207 * - We would like \\( 53 \\) random bits to generate a 53-bit precision integer and, thus, want to discard \\( 11 \\) of the generated bits. 208 * 209 * - We do so by discarding \\( 5 \\) bits from \\( x \\) and \\( 6 \\) bits from \\( y \\). 210 * 211 * - Accordingly, \\( x \\) contains \\( 27 \\) random bits, which are subsequently shifted left \\( 26 \\) bits (multiplied by \\( 2^{26} \\), and \\( y \\) contains \\( 26 \\) random bits to fill in the lower \\( 26 \\) bits. When summed, they combine to comprise \\( 53 \\) random bits of a double-precision floating-point integer. 212 * 213 * - As an example, suppose, for the sake of argument, the 32-bit PRNG generates the maximum unsigned 32-bit integer \\( 2^{32}-1 \\) twice in a row. Then, 214 * 215 * ```c 216 * uint32_t x = 4294967295 >> 5; // 00000111111111111111111111111111 217 * uint32_t y = 4294967295 >> 6; // 00000011111111111111111111111111 218 * ``` 219 * 220 * Multiplying \\( x \\) by \\( 2^{26} \\) returns \\( 9007199187632128 \\), which, in binary, is 221 * 222 * ```binarystring 223 * 0 10000110011 11111111111111111111 11111100000000000000000000000000 224 * ``` 225 * 226 * Adding \\( y \\) yields \\( 9007199254740991 \\) (the maximum "safe" double-precision floating-point integer value), which, in binary, is 227 * 228 * ```binarystring 229 * 0 10000110011 11111111111111111111 11111111111111111111111111111111 230 * ``` 231 * 232 * - Similarly, suppose the 32-bit PRNG generates the following values 233 * 234 * ```c 235 * uint32_t x = 1 >> 5; // 0 => 00000000000000000000000000000000 236 * uint32_t y = 64 >> 6; // 1 => 00000000000000000000000000000001 237 * ``` 238 * 239 * Multiplying \\( x \\) by \\( 2^{26} \\) returns \\( 0 \\), which, in binary, is 240 * 241 * ```binarystring 242 * 0 00000000000 00000000000000000000 00000000000000000000000000000000 243 * ``` 244 * 245 * Adding \\( y \\) yields \\( 1 \\), which, in binary, is 246 * 247 * ```binarystring 248 * 0 01111111111 00000000000000000000 00000000000000000000000000000000 249 * ``` 250 * 251 * - As different combinations of \\( x \\) and \\( y \\) are generated, different combinations of double-precision floating-point exponent and significand bits will be toggled, thus generating pseudorandom double-precision floating-point numbers. 252 * 253 * ## Notes 254 * 255 * - The function returns `-1` if unable to generate a pseudorandom number and `0` otherwise. 256 * 257 * ## References 258 * 259 * - Harase, Shin. 2017. "Conversion of Mersenne Twister to double-precision floating-point numbers." _ArXiv_ abs/1708.06018 (September). <https://arxiv.org/abs/1708.06018>. 260 * 261 * @private 262 * @param obj PRNG object 263 * @param out output address 264 * @return status code 265 */ 266 static inline int8_t normalized( struct BasePRNGObject *obj, double *out ) { 267 uint64_t x; 268 uint64_t y; 269 if ( obj == NULL || obj->prng != &mt19937_prng ) { 270 return -1; 271 } 272 next( obj, &x); 273 x >>= 5; 274 275 next( obj, &y ); 276 y >>= 6; 277 278 // Note: casting `x` and `y` to doubles here is fine, as neither will ever exceed the maximum "safe" double-precision floating-point number: 279 *out = ( ((double)x*TWO_26)+(double)y ) * FLOAT64_NORMALIZATION_CONSTANT; 280 281 return 0; 282 } 283 284 /** 285 * Frees a PRNG's allocated memory. 286 * 287 * @private 288 * @param obj PRNG object 289 */ 290 static inline void mt19937_free( struct BasePRNGObject *obj ) { 291 if ( obj == NULL || obj->prng != &mt19937_prng ) { 292 return; 293 } 294 stdlib_base_random_mt19937_state_t *state = (stdlib_base_random_mt19937_state_t *)( obj->state ); 295 free( state->seed ); 296 free( obj->state ); 297 free( obj ); 298 } 299 300 /** 301 * Returns an initial PRNG state. 302 * 303 * @private 304 * @param state pointer to state array 305 * @param N state array length 306 * @param s seed 307 */ 308 static inline void create_state( uint32_t *state, const int32_t N, const uint32_t s ) { 309 int32_t i; 310 311 // Set the first element of the state array to the provided seed: 312 state[ 0 ] = s; 313 314 // Initialize the remaining state array elements: 315 for ( i = 1; i < N; i++ ) { 316 state[ i ] = (KNUTH_MULTIPLIER * (state[i-1] ^ (state[i-1]>>30)) + i); 317 } 318 } 319 320 /** 321 * Initializes a PRNG state array according to a seed array. 322 * 323 * @private 324 * @param state pointer to state array 325 * @param N state array length 326 * @param seed pointer to seed array 327 * @param M seed array length 328 */ 329 static inline void init_state( uint32_t *state, const int32_t N, const uint32_t *seed, const int64_t M ) { 330 int32_t i; 331 int64_t j; 332 int64_t k; 333 334 i = 1; 335 j = 0; 336 k = ( N > M ) ? N : M; 337 for ( ; k > 0; k-- ) { 338 state[ i ] = (state[i]^((state[i-1]^(state[i-1]>>30))*MAGIC_MULTIPLIER_1)) + seed[j] + j; 339 i += 1; 340 j += 1; 341 if ( i >= N ) { 342 state[ 0 ] = state[ N-1 ]; 343 i = 1; 344 } 345 if ( j >= M ) { 346 j = 0; 347 } 348 } 349 for ( k = N-1; k > 0; k-- ) { 350 state[ i ] = (state[i]^((state[i-1]^(state[i-1]>>30))*MAGIC_MULTIPLIER_2)) - i; 351 i += 1; 352 if ( i >= N ) { 353 state[ 0 ] = state[ N-1 ]; 354 i = 1; 355 } 356 } 357 // Ensure a non-zero initial state array: 358 state[ 0 ] = TWO_32; // MSB (most significant bit) is 1 359 } 360 361 /** 362 * Updates a PRNG's internal state by generating the next `N` words. 363 * 364 * @private 365 * @param state pointer to a PRNG's internal state array 366 * @param N state array length 367 */ 368 static inline void twist( uint32_t *state, const int32_t N ) { 369 uint32_t w; 370 int32_t i; 371 int32_t j; 372 int32_t k; 373 374 k = N - M; 375 for ( i = 0; i < k; i++ ) { 376 w = ( state[i]&UPPER_MASK ) | ( state[i+1]&LOWER_MASK ); 377 state[ i ] = state[ i+M ] ^ ( w>>1 ) ^ MAG01[ w&ONE ]; 378 } 379 j = N - 1; 380 for ( ; i < j; i++ ) { 381 w = ( state[i]&UPPER_MASK ) | ( state[i+1]&LOWER_MASK ); 382 state[ i ] = state[ i-k ] ^ ( w>>1 ) ^ MAG01[ w&ONE ]; 383 } 384 w = ( state[j]&UPPER_MASK ) | ( state[0]&LOWER_MASK ); 385 state[ j ] = state[ M-1 ] ^ ( w>>1 ) ^ MAG01[ w&ONE ]; 386 } 387 388 /** 389 * Returns a pointer to a dynamically allocated PRNG. 390 * 391 * ## Notes 392 * 393 * - The user is responsible for freeing the allocated memory. 394 * 395 * @param seed pointer to a seed array 396 * @param len seed array length 397 * @return pointer to a dynamically allocated PRNG or, if unable to allocate memory, a null pointer 398 * 399 * @example 400 * #include <stdlib.h> 401 * #include <stdio.h> 402 * #include <stdint.h> 403 * #include "stdlib/random/base.h" 404 * #include "stdlib/random/base/mt19937.h" 405 * 406 * // Define a PRNG seed: 407 * uint32_t seed[] = { 12345 }; 408 * 409 * // Create a PRNG: 410 * struct BasePRNGObject *obj = stdlib_base_random_mt19937_allocate( seed, 1 ); 411 * if ( obj == NULL ) { 412 * fprintf( stderr, "Error allocating memory.\n" ); 413 * exit( 1 ); 414 * } 415 * 416 * uint64_t r; 417 * int8_t status = obj->prng->next( obj, &r ); 418 * if ( status != 0 ) { 419 * fprintf( stderr, "Unexpected result.\n" ); 420 * exit( 1 ); 421 * } 422 * 423 * // ... 424 * 425 * status = obj->prng->next( obj, &r ); 426 * 427 * // ... 428 * 429 * status = obj->prng->next( obj, &r ); 430 * 431 * // ... 432 * 433 * // Free allocated memory: 434 * stdlib_base_random_mt19937_free( obj ); 435 */ 436 struct BasePRNGObject * stdlib_base_random_mt19937_allocate( const uint32_t *seed, const int64_t len ) { 437 stdlib_base_random_mt19937_state_t *state; 438 struct BasePRNGObject *obj; 439 uint32_t *iseed; 440 441 obj = malloc( sizeof( struct BasePRNGObject ) ); 442 if ( obj == NULL ) { 443 return NULL; 444 } 445 state = malloc( sizeof( stdlib_base_random_mt19937_state_t ) ); 446 if ( state == NULL ) { 447 free( obj ); // prevent memory leaks 448 return NULL; 449 } 450 obj->prng = &mt19937_prng; 451 obj->state = state; 452 453 // Create an internal copy of the provided seed array to prevent the inability to reproduce PRNG values based on the PRNG's stated seed due to external state mutation: 454 iseed = (uint32_t *)malloc( sizeof( uint32_t )*len ); 455 if ( iseed == NULL ) { 456 free( obj ); // prevent memory leaks 457 free( state ); 458 return NULL; 459 } 460 memcpy( iseed, seed, sizeof( uint32_t )*len ); 461 state->seed = iseed; 462 state->seed_length = len; 463 464 // Initialize the PRNG state: 465 create_state( state->state, N, SEED_ARRAY_INIT_STATE ); 466 init_state( state->state, N, iseed, len ); 467 468 // Set the state index which determines when we need to update the PRNG's internal state: 469 state->i = N; 470 471 return obj; 472 } 473 474 /** 475 * Frees a PRNG's allocated memory. 476 * 477 * @param obj PRNG object 478 * 479 * @example 480 * #include <stdlib.h> 481 * #include <stdio.h> 482 * #include <stdint.h> 483 * #include "stdlib/random/base.h" 484 * #include "stdlib/random/base/mt19937.h" 485 * 486 * // Define a PRNG seed: 487 * uint32_t seed[] = { 12345 }; 488 * 489 * // Create a PRNG: 490 * struct BasePRNGObject *obj = stdlib_base_random_mt19937_allocate( seed, 1 ); 491 * if ( obj == NULL ) { 492 * fprintf( stderr, "Error allocating memory.\n" ); 493 * exit( 1 ); 494 * } 495 * 496 * uint64_t r; 497 * int8_t status = obj->prng->next( obj, &r ); 498 * if ( status != 0 ) { 499 * fprintf( stderr, "Unexpected result.\n" ); 500 * exit( 1 ); 501 * } 502 * 503 * // ... 504 * 505 * status = obj->prng->next( obj, &r ); 506 * 507 * // ... 508 * 509 * status = obj->prng->next( obj, &r ); 510 * 511 * // ... 512 * 513 * // Free allocated memory: 514 * stdlib_base_random_mt19937_free( obj ); 515 */ 516 void stdlib_base_random_mt19937_free( struct BasePRNGObject *obj ) { 517 if ( obj == NULL || obj->prng != &mt19937_prng ) { 518 return; 519 } 520 obj->prng->free( obj ); 521 } 522 523 /** 524 * Returns the PRNG seed length. 525 * 526 * ## Notes 527 * 528 * - The function returns `-1` if unable to resolve a PRNG seed length and `0` otherwise. 529 * 530 * @param obj PRNG object 531 * @param len output address 532 * @return status code 533 * 534 * @example 535 * #include <stdlib.h> 536 * #include <stdio.h> 537 * #include <stdint.h> 538 * #include "stdlib/random/base.h" 539 * #include "stdlib/random/base/mt19937.h" 540 * 541 * // Define a PRNG seed: 542 * uint32_t seed1[] = { 12345 }; 543 * 544 * // Create a PRNG: 545 * struct BasePRNGObject *obj = stdlib_base_random_mt19937_allocate( seed1, 1 ); 546 * if ( obj == NULL ) { 547 * fprintf( stderr, "Error allocating memory.\n" ); 548 * exit( 1 ); 549 * } 550 * 551 * // ... 552 * 553 * // Get the seed length: 554 * int64_t seed_length; 555 * int8_t status = stdlib_base_random_mt19937_seed_length( obj, &seed_length ); 556 * if ( status != 0 ) { 557 * fprintf( stderr, "Error encountered when attempting to retrieve the PRNG seed length.\n" ); 558 * exit( 1 ); 559 * } 560 * 561 * // Get the PRNG seed: 562 * uint32_t *seed2 = (uint32_t *)malloc( sizeof( uint32_t )*seed_length ); 563 * if ( seed2 == NULL ) { 564 * fprintf( stderr, "Error allocating memory.\n" ); 565 * exit( 1 ); 566 * } 567 * status = stdlib_base_random_mt19937_seed( obj, seed2 ); 568 * if ( status != 0 ) { 569 * fprintf( stderr, "Error encountered when attempting to retrieve the PRNG seed.\n" ); 570 * exit( 1 ); 571 * } 572 * 573 * // Use the seed to, e.g., create another PRNG which will generate the same sequence... 574 * 575 * // Free allocated memory: 576 * stdlib_base_random_mt19937_free( obj ); 577 * free( seed2 ); 578 */ 579 int8_t stdlib_base_random_mt19937_seed_length( const struct BasePRNGObject *obj, int64_t *len ) { 580 if ( obj == NULL || obj->prng != &mt19937_prng ) { 581 return -1; 582 } 583 // Retrieve the state object: 584 const stdlib_base_random_mt19937_state_t *state = (stdlib_base_random_mt19937_state_t *)( obj->state ); 585 586 // Set the seed length: 587 *len = (int64_t)( state->seed_length ); 588 589 return 0; 590 } 591 592 /** 593 * Returns a PRNG seed. 594 * 595 * ## Notes 596 * 597 * - The function returns `-1` if unable to resolve a PRNG seed and `0` otherwise. 598 * 599 * @param obj PRNG object 600 * @param seed output address 601 * @return status code 602 * 603 * @example 604 * #include <stdlib.h> 605 * #include <stdio.h> 606 * #include <stdint.h> 607 * #include "stdlib/random/base.h" 608 * #include "stdlib/random/base/mt19937.h" 609 * 610 * // Define a PRNG seed: 611 * uint32_t seed1[] = { 12345 }; 612 * 613 * // Create a PRNG: 614 * struct BasePRNGObject *obj = stdlib_base_random_mt19937_allocate( seed1, 1 ); 615 * if ( obj == NULL ) { 616 * fprintf( stderr, "Error allocating memory.\n" ); 617 * exit( 1 ); 618 * } 619 * 620 * // ... 621 * 622 * // Get the seed length: 623 * int64_t seed_length; 624 * int8_t status = stdlib_base_random_mt19937_seed_length( obj, &seed_length ); 625 * if ( status != 0 ) { 626 * fprintf( stderr, "Error encountered when attempting to retrieve the PRNG seed length.\n" ); 627 * exit( 1 ); 628 * } 629 * 630 * // Get the PRNG seed: 631 * uint32_t *seed2 = (uint32_t *)malloc( sizeof( uint32_t )*seed_length ); 632 * if ( seed2 == NULL ) { 633 * fprintf( stderr, "Error allocating memory.\n" ); 634 * exit( 1 ); 635 * } 636 * status = stdlib_base_random_mt19937_seed( obj, seed2 ); 637 * if ( status != 0 ) { 638 * fprintf( stderr, "Error encountered when attempting to retrieve the PRNG seed.\n" ); 639 * exit( 1 ); 640 * } 641 * 642 * // Use the seed to, e.g., create another PRNG which will generate the same sequence... 643 * 644 * // Free allocated memory: 645 * stdlib_base_random_mt19937_free( obj ); 646 * free( seed2 ); 647 */ 648 int8_t stdlib_base_random_mt19937_seed( const struct BasePRNGObject *obj, uint32_t *seed ) { 649 if ( obj == NULL || obj->prng != &mt19937_prng ) { 650 return -1; 651 } 652 // Retrieve the state object: 653 const stdlib_base_random_mt19937_state_t *state = (stdlib_base_random_mt19937_state_t *)( obj->state ); 654 655 // Copy the seed array: 656 memcpy( seed, state->seed, sizeof( uint32_t )*(state->seed_length) ); 657 658 return 0; 659 } 660 661 /** 662 * Returns a **copy** of the current PRNG state. 663 * 664 * ## Notes 665 * 666 * - The user is responsible for freeing the allocated memory. 667 * 668 * @param obj PRNG object 669 * @return pointer to a copy of the PRNG's internal state or, if unable to allocate memory, a null pointer 670 * 671 * @example 672 * #include <stdlib.h> 673 * #include <stdio.h> 674 * #include <stdint.h> 675 * #include "stdlib/random/base.h" 676 * #include "stdlib/random/base/mt19937.h" 677 * 678 * // Define a PRNG seed: 679 * uint32_t seed[] = { 12345 }; 680 * 681 * // Create a PRNG: 682 * struct BasePRNGObject *obj = stdlib_base_random_mt19937_allocate( seed, 1 ); 683 * if ( obj == NULL ) { 684 * fprintf( stderr, "Error allocating memory.\n" ); 685 * exit( 1 ); 686 * } 687 * 688 * stdlib_base_random_mt19937_state_t *state = (stdlib_base_random_mt19937_state_t *)stdlib_base_random_mt19937_state( obj ); 689 * if ( state == NULL ) { 690 * fprintf( stderr, "Unable to retrieve PRNG state.\n" ); 691 * exit( 1 ); 692 * } 693 * 694 * // Use the captured state to, e.g., sync another PRNG or to reset a PRNG to a particular state in order to "replay" generated values at a later point in time... 695 * 696 * // Free allocated memory: 697 * stdlib_base_random_mt19937_free( obj ); 698 * 699 * free( state->seed ); 700 * free( state ); 701 */ 702 void * stdlib_base_random_mt19937_state( const struct BasePRNGObject *obj ) { 703 stdlib_base_random_mt19937_state_t *state; 704 stdlib_base_random_mt19937_state_t *so; 705 uint64_t nbytes; 706 uint32_t *seed; 707 if ( obj == NULL || obj->prng != &mt19937_prng ) { 708 return NULL; 709 } 710 state = (stdlib_base_random_mt19937_state_t *)malloc( obj->prng->state_size ); 711 if ( state == NULL ) { 712 return NULL; 713 } 714 nbytes = sizeof( uint32_t ) * (state->seed_length); 715 seed = (uint32_t *)malloc( nbytes ); 716 if ( seed == NULL ) { 717 free( state ); // prevent memory leaks 718 return NULL; 719 } 720 // Copy the state: 721 memcpy( state, obj->state, obj->prng->state_size ); 722 723 // Explicitly copy the seed array to prevent external mutation: 724 so = (stdlib_base_random_mt19937_state_t *)( obj->state ); 725 memcpy( seed, so->seed, nbytes ); 726 state->seed = seed; 727 728 return (void *)state; 729 } 730 731 /** 732 * Sets the PRNG state. 733 * 734 * ## Notes 735 * 736 * - The function returns `-1` if unable to set a PRNG state and `0` otherwise. 737 * 738 * @param obj PRNG object 739 * @param state state 740 * @return status code 741 * 742 * @example 743 * #include <stdlib.h> 744 * #include <stdio.h> 745 * #include <stdint.h> 746 * #include "stdlib/random/base.h" 747 * #include "stdlib/random/base/mt19937.h" 748 * 749 * // Define a PRNG seed: 750 * uint32_t seed[] = { 12345 }; 751 * 752 * // Create a PRNG: 753 * struct BasePRNGObject *obj = stdlib_base_random_mt19937_allocate( seed, 1 ); 754 * if ( obj == NULL ) { 755 * fprintf( stderr, "Error allocating memory.\n" ); 756 * exit( 1 ); 757 * } 758 * 759 * uint64_t r; 760 * int8_t status = obj->prng->next( obj, &r ); 761 * if ( status != 0 ) { 762 * fprintf( stderr, "Unexpected result.\n" ); 763 * exit( 1 ); 764 * } 765 * 766 * // ... 767 * 768 * status = obj->prng->next( obj, &r ); 769 * 770 * // ... 771 * 772 * status = obj->prng->next( obj, &r ); 773 * 774 * // ... 775 * 776 * // Retrieve the current PRNG state... 777 * stdlib_base_random_mt19937_state_t *state = (stdlib_base_random_mt19937_state_t *)stdlib_base_random_mt19937_state( obj ); 778 * if ( state == NULL ) { 779 * fprintf( stderr, "Error encountered when attempting to retrieve PRNG state.\n" ); 780 * exit( 1 ); 781 * } 782 * 783 * // ... 784 * 785 * status = obj->prng->next( obj, &r ); 786 * 787 * // ... 788 * 789 * status = obj->prng->next( obj, &r ); 790 * 791 * // ... 792 * 793 * // Reset the PRNG to a previous state... 794 * status = stdlib_base_random_mt19937_set( obj, (void *)state ); 795 * if ( status != 0 ) { 796 * fprintf( stderr, "Error encountered when attempting to set PRNG state.\n" ); 797 * exit( 1 ); 798 * } 799 * 800 * // ... 801 * 802 * status = obj->prng->next( obj, &r ); 803 * 804 * // ... 805 * 806 * status = obj->prng->next( obj, &r ); 807 * 808 * // ... 809 * 810 * // Free allocated memory: 811 * stdlib_base_random_mt19937_free( obj ); 812 * 813 * free( state->seed ); 814 * free( state ); 815 */ 816 int8_t stdlib_base_random_mt19937_set( struct BasePRNGObject *obj, const void *state ) { 817 stdlib_base_random_mt19937_state_t *vstate; 818 uint64_t nbytes; 819 uint32_t *seed; 820 if ( obj == NULL || state == NULL || obj->prng != &mt19937_prng ) { 821 return -1; 822 } 823 // Copy the provided seed array: 824 vstate = ( stdlib_base_random_mt19937_state_t *)state; 825 nbytes = sizeof( uint32_t ) * ( vstate->seed_length ); 826 seed = (uint32_t *)malloc( nbytes ); 827 if ( seed == NULL ) { 828 return -1; 829 } 830 memcpy( seed, vstate->seed, nbytes ); 831 832 // Retrieve the current PRNG state: 833 vstate = ( stdlib_base_random_mt19937_state_t *)( obj->state ); 834 835 // Free the memory held by the current seed array: 836 free( vstate->seed ); 837 838 // Overwrite the current state with the provided state: 839 memcpy( vstate, state, obj->prng->state_size ); 840 841 // Update the seed array pointer: 842 vstate->seed = seed; 843 844 return 0; 845 }