tt800.h
#ifndef TT800_H
#define TT800_H
#include <stdint.h>
typedef struct
{
uint32_t state_array[25]; // the array for the state vector
int state_index; // index into state vector array
} tt_state;
uint32_t random_uint32(tt_state* state);
void seed_initial_state(tt_state* state, uint32_t seed);
void set_initial_state_key(tt_state* state, char* key);
void set_initial_state(tt_state* state, uint32_t* seed_array);
#endif
tt800.c
/* A C-program for TT800 : July 8th 1996 Version
by M. Matsumoto, email: m-mat @ math.sci.hiroshima-u.ac.jp
Formatting modifications for streamlined performance and
better readability by Robert Bristow-Johnson April 14th 2024
Also added additional initialization functions similar to the
MT19937 utility.
random_uint32(tt_state* state) generates and returns one
pseudorandom unsigned integer (32bit) which is uniformly
distributed from 0 to 2^32 - 1.
seed_initial_state(tt_state* state, uint32_t seed) sets initial
values of the PRNG state of 25 words according to a given single
32-bit seed word.
set_initial_state_key(tt_state* state, char* key) sets the initial
state according to the text of a key in a given string of chars.
set_initial_state(tt_state* state, uint32_t* seed_array) sets the
initial state to exactly the given seed_array.
Before random_uint32() is called, a tt_state must be created and
seed_initial_state() or set_initial_state_key() or
set_initial_state() must be called once. One may choose any
initial 25 values except all zeros.
Copyright (C) 1996, Makoto Matsumoto
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.
See: ACM Transactions on Modelling and Computer Simulation,
Vol. 4, No. 3, 1994, pages 254-266.
*/
#include "tt800.h"
// Period parameters
#define N 25
#define M 7 // not used directly in this version
#define K 18 // redefined from N-M
#define MATRIX_A 0x8ebfd028UL // constant vector A
uint32_t random_uint32(tt_state* state)
{
uint32_t* state_array = &(state->state_array[0]);
int n = state->state_index; // 0 <= state_index <= N-1 always
uint32_t x = state_array[n]; // get state N iterations ago
uint32_t xA = x >> 1;
if (x & 0x00000001UL) xA ^= MATRIX_A;
int k = n - K; // point to state K iterations ago
if (k < 0) k += N; // modulo N circular indexing
x = state_array[k] ^ xA; // generate next value in the state
state_array[n++] = x; // update new state
if (n >= N) n = 0; // modulo N circular indexing
state->state_index = n;
// tempering
x ^= (x << 7) & 0x2b5b2500UL; // s and b, magic vectors
x ^= (x << 15) & 0xdb8b0000UL; // t and c, magic vectors
x ^= (x >> 16); // this line added by Makoto Matsumoto in 1996 to improve lower bits corellation.
return x;
}
/*
Initializing the state_array from a seed
*/
void seed_initial_state(tt_state* state, uint32_t seed)
{
uint32_t* state_array = &(state->state_array[0]);
for (int n=0; n<N; n++)
{
seed = 1812433253UL * (seed ^ (seed >> 30)) + n; // Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
state_array[n] = seed; // suggested initial seed = 19650218UL
}
state->state_index = 0;
}
/*
Initializing the state_array from a text key.
This is, hopefully, well scrambled but is a fully deterministic
function of the key, which must be at least 8 characters. If the
key is less than 8 characters, the PRNG state is still adequately
initialized and the default seed is used.
*/
void set_initial_state_key(tt_state* state, char* key)
{
seed_initial_state(state, 19650218UL);
uint32_t* state_array = &(state->state_array[0]);
int offset = 0;
int k = 0;
while ((key[k] != '\0') && (k < 4*N)) // determine string length, stop at 4N
{
offset += (int)key[k++]; // see how many times we circle around the ASCII table.
}
if (k >= 8) // key must be at least 8 chars
{
offset &= 0x007f;
offset += N-128; // N-128 <= offset <= N-1
k -= 3; // shorten reach by 3 chars
int i = 0;
for (int n=0; n<N; n++)
{
uint32_t key28bit = ( ((uint32_t)key[i++] & 0x0000007fUL) << 21)
| ( ((uint32_t)key[i++] & 0x0000007fUL) << 14)
| ( ((uint32_t)key[i++] & 0x0000007fUL) << 7)
| ( ((uint32_t)key[i++] & 0x0000007fUL) );
if (i >= k) i -= k; // wrap i around
state_array[n] += 1664525UL * (key28bit + n);
int m = n - offset;
if (m < 0) m += N; // modulo N
state_array[n] ^= 1566083941UL * (state_array[m] ^ (state_array[m] >> 30));
}
}
uint32_t alt_state_array[N];
for (int n=0; n<N; n++)
{
alt_state_array[n] = random_uint32(state); // scramble it up a bit with tempered random values
}
for (int n=0; n<N; n++)
{
state_array[n] = alt_state_array[(N-1)-n]; // swap with alternate state and reverse order
}
for (int n=0; n<2*N; n++)
{
random_uint32(state); // this should scramble it up enough to dash any hope of reverse engineering the key
}
}
/*
Initialization by "seed_initial_state()" is an example.
Theoretically, there are 2^800-1 possible states as an intial
state. This function allows to choose any of 2^800-1 states.
Essential bits in "seed_array[]" are the following 800 bits:
seed_array[0], seed_array[1], ..., seed_array[N-1].
Theoretically, seed_array[0], seed_array[1], ..., seed_array[N-1]
can take any values except all zeros.
The sizeof(seed_array[]) must be at least sizeof(state_array[]) = N = 25
*/
void set_initial_state(tt_state* state, uint32_t* seed_array)
{
uint32_t* state_array = &(state->state_array[0]);
for (int n=0; n<N; n++)
{
state_array[n] = seed_array[n];
}
state->state_index = 0;
}
/* This main() outputs first 1000 generated numbers.
#include <stdio.h>
#include "tt800.h"
main()
{
tt_state state;
seed_initial_state(&state, 19650218UL);
for (int i=0; i<1000; i++)
{
printf("%10lu ", random_uint32(&state));
if (i%5==4) printf("\n");
}
}
*/
RandomNumber(vec2 seed, float x, float y) { return fract(sin(dot(seed + vec2(fx, fy), vec2(12.9898,78.233))) * 43758.5453); }
(GLSL ES) – Odoric