time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

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 }