mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-14 22:42:14 -07:00
Turn things in common into separate libs.
Took 2 hours 27 minutes
This commit is contained in:
parent
53d80efab8
commit
01378b8314
389 changed files with 336 additions and 233 deletions
30
libs/rng/src/rng_abstract.cpp
Normal file
30
libs/rng/src/rng_abstract.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "../include/rng/rng_abstract.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
QVector<int> RNG_Abstract::makeNumbersVector(int n, int min, int max)
|
||||
{
|
||||
const int bins = max - min + 1;
|
||||
QVector<int> result(bins);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int number = rand(min, max);
|
||||
if ((number < min) || (number > max))
|
||||
qDebug() << "rand(" << min << "," << max << ") returned " << number;
|
||||
else
|
||||
result[number - min]++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double RNG_Abstract::testRandom(const QVector<int> &numbers) const
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < numbers.size(); ++i)
|
||||
n += numbers[i];
|
||||
double expected = (double)n / (double)numbers.size();
|
||||
double chisq = 0;
|
||||
for (int i = 0; i < numbers.size(); ++i)
|
||||
chisq += ((double)numbers[i] - expected) * ((double)numbers[i] - expected) / expected;
|
||||
|
||||
return chisq;
|
||||
}
|
||||
137
libs/rng/src/rng_sfmt.cpp
Normal file
137
libs/rng/src/rng_sfmt.cpp
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#include "../include/rng/rng_sfmt.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <stdexcept>
|
||||
|
||||
// This is from gcc sources, namely from fixincludes/inclhack.def
|
||||
// On C++11 systems, <cstdint> could be included instead.
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX (~(uint64_t)0)
|
||||
#endif
|
||||
|
||||
RNG_SFMT::RNG_SFMT(QObject *parent) : RNG_Abstract(parent)
|
||||
{
|
||||
// initialize the random number generator with a 32bit integer seed (timestamp)
|
||||
sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toSecsSinceEpoch());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is the rand() equivalent which calls the cdf with proper bounds.
|
||||
*
|
||||
* It is possible to generate random numbers from [-min, +/-max] though the RNG uses
|
||||
* unsigned numbers only, so this wrapper handles some special cases for min and max.
|
||||
*
|
||||
* It is only necessary that the upper bound is larger or equal to the lower bound - with the exception
|
||||
* that someone wants something like rand() % -foo.
|
||||
*/
|
||||
unsigned int RNG_SFMT::rand(int min, int max)
|
||||
{
|
||||
/* If min is negative, it would be possible to calculate
|
||||
* cdf(0, max - min) + min
|
||||
* There has been no use for negative random numbers with rand() though, so it's treated as error.
|
||||
*/
|
||||
if (min < 0) {
|
||||
throw std::invalid_argument(
|
||||
QString("Invalid bounds for RNG: Got min " + QString::number(min) + " < 0!\n").toStdString());
|
||||
// at this point, the method exits. No return value is needed, because
|
||||
// basically the exception itself is returned.
|
||||
}
|
||||
|
||||
// For complete fairness and equal timing, this should be a roll, but let's skip it anyway
|
||||
if (min == max)
|
||||
return max;
|
||||
|
||||
// This is actually not used in Cockatrice:
|
||||
// Someone wants rand() % -foo, so we should compute -rand(0, +foo)
|
||||
// But this method returns an unsigned int, so it doesn't really make
|
||||
// a difference.
|
||||
// This is the only time when min > max is (sort of) legal.
|
||||
// Not handling this will cause the application to crash.
|
||||
if (min == 0 && max < 0) {
|
||||
return cdf(0, -max);
|
||||
}
|
||||
|
||||
// No special cases are left, except !(min > max) which is caught in the cdf itself.
|
||||
return cdf(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Much thought went into this, please read this comment before you modify the code.
|
||||
* Let SFMT() be an alias for sfmt_genrand_uint64() aka SFMT's rand() function.
|
||||
*
|
||||
* SMFT() returns a uniformly distributed pseudorandom number from 0 to UINT64_MAX.
|
||||
* As SFMT() operates on a limited integer range, it is a _discrete_ function.
|
||||
*
|
||||
* We want a random number from a given interval [min, max] though, so we need to
|
||||
* implement the (discrete) cumulative distribution function SFMT(min, max), which
|
||||
* returns a random number X from [min, max].
|
||||
*
|
||||
* This CDF is by formal definition:
|
||||
* SFMT(X; min, max) = (floor(X) - min + 1) / (max - min + 1)
|
||||
*
|
||||
* To get out the random variable, solve for X:
|
||||
* floor(X) = SFMT(X; min, max) * (max - min + 1) + min - 1
|
||||
* So this is, what rand(min, max) should look like.
|
||||
* Problem: SFMT(X; min, max) * (max - min + 1) could produce an integer overflow,
|
||||
* so it is not safe.
|
||||
*
|
||||
* One solution is to divide the universe into buckets of equal size depending on the
|
||||
* range [min, max] and assign X to the bucket that contains the number generated
|
||||
* by SFMT(). This equals to modulo computation and is not satisfying:
|
||||
* If the buckets don't divide the universe equally, because the bucket size is not
|
||||
* a divisor of 2, there will be a range in the universe that is biased because one
|
||||
* bucket is too small thus will be chosen less equally!
|
||||
*
|
||||
* This is solved by rejection sampling:
|
||||
* As SFMT() is assumed to be unbiased, we are allowed to ignore those random numbers
|
||||
* from SFMT() that would force us to have an unequal bucket and generate new random
|
||||
* numbers until one number fits into one of the other buckets.
|
||||
* This can be compared to an ideal six sided die that is rolled until only sides
|
||||
* 1-5 show up, while 6 represents something that you don't want. So you basically roll
|
||||
* a five sided die.
|
||||
*
|
||||
* Note: If you replace the SFMT RNG with some other rand() function in the future,
|
||||
* then you _need_ to change the UINT64_MAX constant to the largest possible random
|
||||
* number which can be created by the new rand() function. This value is often defined
|
||||
* in a RAND_MAX constant.
|
||||
* Otherwise you will probably skew the outcome of the rand() method or worsen the
|
||||
* performance of the application.
|
||||
*/
|
||||
unsigned int RNG_SFMT::cdf(unsigned int min, unsigned int max)
|
||||
{
|
||||
// This all makes no sense if min > max, which should never happen.
|
||||
if (min > max) {
|
||||
throw std::invalid_argument(QString("Invalid bounds for RNG: min > max! Values were: min = " +
|
||||
QString::number(min) + ", max = " + QString::number(max))
|
||||
.toStdString());
|
||||
// at this point, the method exits. No return value is needed, because
|
||||
// basically the exception itself is returned.
|
||||
}
|
||||
|
||||
// First compute the diameter (aka size, length) of the [min, max] interval
|
||||
const unsigned int diameter = max - min + 1;
|
||||
|
||||
// Compute how many buckets (each in size of the diameter) will fit into the
|
||||
// universe.
|
||||
// If the division has a remainder, the result is floored automatically.
|
||||
const uint64_t buckets = UINT64_MAX / diameter;
|
||||
|
||||
// Compute the last valid random number. All numbers beyond have to be ignored.
|
||||
// If there was no remainder in the previous step, limit is equal to UINT64_MAX.
|
||||
const uint64_t limit = diameter * buckets;
|
||||
|
||||
uint64_t rand;
|
||||
// To make the random number generation thread-safe, a mutex is created around
|
||||
// the generation. Outside of the loop of course, to avoid lock/unlock overhead.
|
||||
mutex.lock();
|
||||
do {
|
||||
rand = sfmt_genrand_uint64(&sfmt);
|
||||
} while (rand >= limit);
|
||||
mutex.unlock();
|
||||
|
||||
// Now determine the bucket containing the SFMT() random number and after adding
|
||||
// the lower bound, a random number from [min, max] can be returned.
|
||||
return (unsigned int)(rand / buckets + min);
|
||||
}
|
||||
437
libs/rng/src/sfmt/SFMT.c
Normal file
437
libs/rng/src/sfmt/SFMT.c
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/**
|
||||
* @file SFMT.c
|
||||
* @brief SIMD oriented Fast Mersenne Twister(SFMT)
|
||||
*
|
||||
* @author Mutsuo Saito (Hiroshima University)
|
||||
* @author Makoto Matsumoto (Hiroshima University)
|
||||
*
|
||||
* Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
|
||||
* University.
|
||||
* Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
|
||||
* University and The University of Tokyo.
|
||||
* Copyright (C) 2013 Mutsuo Saito, Makoto Matsumoto and Hiroshima
|
||||
* University.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The 3-clause BSD License is applied to this software, see
|
||||
* LICENSE.txt
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "../include/rng/sfmt/SFMT.h"
|
||||
#include "../include/rng/sfmt/SFMT-params.h"
|
||||
#include "../include/rng/sfmt/SFMT-common.h"
|
||||
|
||||
#if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64)
|
||||
#define BIG_ENDIAN64 1
|
||||
#endif
|
||||
#if defined(HAVE_ALTIVEC) && !defined(BIG_ENDIAN64)
|
||||
#define BIG_ENDIAN64 1
|
||||
#endif
|
||||
#if defined(ONLY64) && !defined(BIG_ENDIAN64)
|
||||
#if defined(__GNUC__)
|
||||
#error "-DONLY64 must be specified with -DBIG_ENDIAN64"
|
||||
#endif
|
||||
#undef ONLY64
|
||||
#endif
|
||||
|
||||
/*----------------
|
||||
STATIC FUNCTIONS
|
||||
----------------*/
|
||||
inline static int idxof(int i);
|
||||
inline static void gen_rand_array(sfmt_t * sfmt, w128_t *array, int size);
|
||||
inline static uint32_t func1(uint32_t x);
|
||||
inline static uint32_t func2(uint32_t x);
|
||||
static void period_certification(sfmt_t * sfmt);
|
||||
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
|
||||
inline static void swap(w128_t *array, int size);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ALTIVEC)
|
||||
#include "SFMT-alti.h"
|
||||
#elif defined(HAVE_SSE2)
|
||||
/**
|
||||
* parameters used by sse2.
|
||||
*/
|
||||
static const w128_t sse2_param_mask = {{SFMT_MSK1, SFMT_MSK2,
|
||||
SFMT_MSK3, SFMT_MSK4}};
|
||||
#if defined(_MSC_VER)
|
||||
#include "SFMT-sse2-msc.h"
|
||||
#else
|
||||
#include "SFMT-sse2.h"
|
||||
#endif
|
||||
#elif defined(HAVE_NEON)
|
||||
#include "SFMT-neon.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function simulate a 64-bit index of LITTLE ENDIAN
|
||||
* in BIG ENDIAN machine.
|
||||
*/
|
||||
#ifdef ONLY64
|
||||
inline static int idxof(int i) {
|
||||
return i ^ 1;
|
||||
}
|
||||
#else
|
||||
inline static int idxof(int i) {
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2)) && (!defined(HAVE_NEON))
|
||||
/**
|
||||
* This function fills the user-specified array with pseudorandom
|
||||
* integers.
|
||||
*
|
||||
* @param sfmt SFMT internal state
|
||||
* @param array an 128-bit array to be filled by pseudorandom numbers.
|
||||
* @param size number of 128-bit pseudorandom numbers to be generated.
|
||||
*/
|
||||
inline static void gen_rand_array(sfmt_t * sfmt, w128_t *array, int size) {
|
||||
int i, j;
|
||||
w128_t *r1, *r2;
|
||||
|
||||
r1 = &sfmt->state[SFMT_N - 2];
|
||||
r2 = &sfmt->state[SFMT_N - 1];
|
||||
for (i = 0; i < SFMT_N - SFMT_POS1; i++) {
|
||||
do_recursion(&array[i], &sfmt->state[i], &sfmt->state[i + SFMT_POS1], r1, r2);
|
||||
r1 = r2;
|
||||
r2 = &array[i];
|
||||
}
|
||||
for (; i < SFMT_N; i++) {
|
||||
do_recursion(&array[i], &sfmt->state[i],
|
||||
&array[i + SFMT_POS1 - SFMT_N], r1, r2);
|
||||
r1 = r2;
|
||||
r2 = &array[i];
|
||||
}
|
||||
for (; i < size - SFMT_N; i++) {
|
||||
do_recursion(&array[i], &array[i - SFMT_N],
|
||||
&array[i + SFMT_POS1 - SFMT_N], r1, r2);
|
||||
r1 = r2;
|
||||
r2 = &array[i];
|
||||
}
|
||||
for (j = 0; j < 2 * SFMT_N - size; j++) {
|
||||
sfmt->state[j] = array[j + size - SFMT_N];
|
||||
}
|
||||
for (; i < size; i++, j++) {
|
||||
do_recursion(&array[i], &array[i - SFMT_N],
|
||||
&array[i + SFMT_POS1 - SFMT_N], r1, r2);
|
||||
r1 = r2;
|
||||
r2 = &array[i];
|
||||
sfmt->state[j] = array[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BIG_ENDIAN64) && !defined(ONLY64) && !defined(HAVE_ALTIVEC)
|
||||
inline static void swap(w128_t *array, int size) {
|
||||
int i;
|
||||
uint32_t x, y;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
x = array[i].u[0];
|
||||
y = array[i].u[2];
|
||||
array[i].u[0] = array[i].u[1];
|
||||
array[i].u[2] = array[i].u[3];
|
||||
array[i].u[1] = x;
|
||||
array[i].u[3] = y;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* This function represents a function used in the initialization
|
||||
* by init_by_array
|
||||
* @param x 32-bit integer
|
||||
* @return 32-bit integer
|
||||
*/
|
||||
static uint32_t func1(uint32_t x) {
|
||||
return (x ^ (x >> 27)) * (uint32_t)1664525UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function represents a function used in the initialization
|
||||
* by init_by_array
|
||||
* @param x 32-bit integer
|
||||
* @return 32-bit integer
|
||||
*/
|
||||
static uint32_t func2(uint32_t x) {
|
||||
return (x ^ (x >> 27)) * (uint32_t)1566083941UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function certificate the period of 2^{MEXP}
|
||||
* @param sfmt SFMT internal state
|
||||
*/
|
||||
static void period_certification(sfmt_t * sfmt) {
|
||||
uint32_t inner = 0;
|
||||
int i, j;
|
||||
uint32_t work;
|
||||
uint32_t *psfmt32 = &sfmt->state[0].u[0];
|
||||
const uint32_t parity[4] = {SFMT_PARITY1, SFMT_PARITY2,
|
||||
SFMT_PARITY3, SFMT_PARITY4};
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
inner ^= psfmt32[idxof(i)] & parity[i];
|
||||
}
|
||||
for (i = 16; i > 0; i >>= 1) {
|
||||
inner ^= inner >> i;
|
||||
}
|
||||
inner &= 1;
|
||||
/* check OK */
|
||||
if (inner == 1) {
|
||||
return;
|
||||
}
|
||||
/* check NG, and modification */
|
||||
for (i = 0; i < 4; i++) {
|
||||
work = 1;
|
||||
for (j = 0; j < 32; j++) {
|
||||
if ((work & parity[i]) != 0) {
|
||||
psfmt32[idxof(i)] ^= work;
|
||||
return;
|
||||
}
|
||||
work = work << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------
|
||||
PUBLIC FUNCTIONS
|
||||
----------------*/
|
||||
#define UNUSED_VARIABLE(x) (void)(x)
|
||||
/**
|
||||
* This function returns the identification string.
|
||||
* The string shows the word size, the Mersenne exponent,
|
||||
* and all parameters of this generator.
|
||||
* @param sfmt SFMT internal state
|
||||
*/
|
||||
const char *sfmt_get_idstring(sfmt_t * sfmt) {
|
||||
UNUSED_VARIABLE(sfmt);
|
||||
return SFMT_IDSTR;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the minimum size of array used for \b
|
||||
* fill_array32() function.
|
||||
* @param sfmt SFMT internal state
|
||||
* @return minimum size of array used for fill_array32() function.
|
||||
*/
|
||||
int sfmt_get_min_array_size32(sfmt_t * sfmt) {
|
||||
UNUSED_VARIABLE(sfmt);
|
||||
return SFMT_N32;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the minimum size of array used for \b
|
||||
* fill_array64() function.
|
||||
* @param sfmt SFMT internal state
|
||||
* @return minimum size of array used for fill_array64() function.
|
||||
*/
|
||||
int sfmt_get_min_array_size64(sfmt_t * sfmt) {
|
||||
UNUSED_VARIABLE(sfmt);
|
||||
return SFMT_N64;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_SSE2) && !defined(HAVE_ALTIVEC) && !defined(HAVE_NEON)
|
||||
/**
|
||||
* This function fills the internal state array with pseudorandom
|
||||
* integers.
|
||||
* @param sfmt SFMT internal state
|
||||
*/
|
||||
void sfmt_gen_rand_all(sfmt_t * sfmt) {
|
||||
int i;
|
||||
w128_t *r1, *r2;
|
||||
|
||||
r1 = &sfmt->state[SFMT_N - 2];
|
||||
r2 = &sfmt->state[SFMT_N - 1];
|
||||
for (i = 0; i < SFMT_N - SFMT_POS1; i++) {
|
||||
do_recursion(&sfmt->state[i], &sfmt->state[i],
|
||||
&sfmt->state[i + SFMT_POS1], r1, r2);
|
||||
r1 = r2;
|
||||
r2 = &sfmt->state[i];
|
||||
}
|
||||
for (; i < SFMT_N; i++) {
|
||||
do_recursion(&sfmt->state[i], &sfmt->state[i],
|
||||
&sfmt->state[i + SFMT_POS1 - SFMT_N], r1, r2);
|
||||
r1 = r2;
|
||||
r2 = &sfmt->state[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ONLY64
|
||||
/**
|
||||
* This function generates pseudorandom 32-bit integers in the
|
||||
* specified array[] by one call. The number of pseudorandom integers
|
||||
* is specified by the argument size, which must be at least 624 and a
|
||||
* multiple of four. The generation by this function is much faster
|
||||
* than the following gen_rand function.
|
||||
*
|
||||
* For initialization, init_gen_rand or init_by_array must be called
|
||||
* before the first call of this function. This function can not be
|
||||
* used after calling gen_rand function, without initialization.
|
||||
*
|
||||
* @param sfmt SFMT internal state
|
||||
* @param array an array where pseudorandom 32-bit integers are filled
|
||||
* by this function. The pointer to the array must be \b "aligned"
|
||||
* (namely, must be a multiple of 16) in the SIMD version, since it
|
||||
* refers to the address of a 128-bit integer. In the standard C
|
||||
* version, the pointer is arbitrary.
|
||||
*
|
||||
* @param size the number of 32-bit pseudorandom integers to be
|
||||
* generated. size must be a multiple of 4, and greater than or equal
|
||||
* to (MEXP / 128 + 1) * 4.
|
||||
*
|
||||
* @note \b memalign or \b posix_memalign is available to get aligned
|
||||
* memory. Mac OSX doesn't have these functions, but \b malloc of OSX
|
||||
* returns the pointer to the aligned memory block.
|
||||
*/
|
||||
void sfmt_fill_array32(sfmt_t * sfmt, uint32_t *array, int size) {
|
||||
assert(sfmt->idx == SFMT_N32);
|
||||
assert(size % 4 == 0);
|
||||
assert(size >= SFMT_N32);
|
||||
|
||||
gen_rand_array(sfmt, (w128_t *)array, size / 4);
|
||||
sfmt->idx = SFMT_N32;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function generates pseudorandom 64-bit integers in the
|
||||
* specified array[] by one call. The number of pseudorandom integers
|
||||
* is specified by the argument size, which must be at least 312 and a
|
||||
* multiple of two. The generation by this function is much faster
|
||||
* than the following gen_rand function.
|
||||
*
|
||||
* @param sfmt SFMT internal state
|
||||
* For initialization, init_gen_rand or init_by_array must be called
|
||||
* before the first call of this function. This function can not be
|
||||
* used after calling gen_rand function, without initialization.
|
||||
*
|
||||
* @param array an array where pseudorandom 64-bit integers are filled
|
||||
* by this function. The pointer to the array must be "aligned"
|
||||
* (namely, must be a multiple of 16) in the SIMD version, since it
|
||||
* refers to the address of a 128-bit integer. In the standard C
|
||||
* version, the pointer is arbitrary.
|
||||
*
|
||||
* @param size the number of 64-bit pseudorandom integers to be
|
||||
* generated. size must be a multiple of 2, and greater than or equal
|
||||
* to (MEXP / 128 + 1) * 2
|
||||
*
|
||||
* @note \b memalign or \b posix_memalign is available to get aligned
|
||||
* memory. Mac OSX doesn't have these functions, but \b malloc of OSX
|
||||
* returns the pointer to the aligned memory block.
|
||||
*/
|
||||
void sfmt_fill_array64(sfmt_t * sfmt, uint64_t *array, int size) {
|
||||
assert(sfmt->idx == SFMT_N32);
|
||||
assert(size % 2 == 0);
|
||||
assert(size >= SFMT_N64);
|
||||
|
||||
gen_rand_array(sfmt, (w128_t *)array, size / 2);
|
||||
sfmt->idx = SFMT_N32;
|
||||
|
||||
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
|
||||
swap((w128_t *)array, size /2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function initializes the internal state array with a 32-bit
|
||||
* integer seed.
|
||||
*
|
||||
* @param sfmt SFMT internal state
|
||||
* @param seed a 32-bit integer used as the seed.
|
||||
*/
|
||||
void sfmt_init_gen_rand(sfmt_t * sfmt, uint32_t seed) {
|
||||
int i;
|
||||
|
||||
uint32_t *psfmt32 = &sfmt->state[0].u[0];
|
||||
|
||||
psfmt32[idxof(0)] = seed;
|
||||
for (i = 1; i < SFMT_N32; i++) {
|
||||
psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)]
|
||||
^ (psfmt32[idxof(i - 1)] >> 30))
|
||||
+ i;
|
||||
}
|
||||
sfmt->idx = SFMT_N32;
|
||||
period_certification(sfmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function initializes the internal state array,
|
||||
* with an array of 32-bit integers used as the seeds
|
||||
* @param sfmt SFMT internal state
|
||||
* @param init_key the array of 32-bit integers, used as a seed.
|
||||
* @param key_length the length of init_key.
|
||||
*/
|
||||
void sfmt_init_by_array(sfmt_t * sfmt, uint32_t *init_key, int key_length) {
|
||||
int i, j, count;
|
||||
uint32_t r;
|
||||
int lag;
|
||||
int mid;
|
||||
int size = SFMT_N * 4;
|
||||
uint32_t *psfmt32 = &sfmt->state[0].u[0];
|
||||
|
||||
if (size >= 623) {
|
||||
lag = 11;
|
||||
} else if (size >= 68) {
|
||||
lag = 7;
|
||||
} else if (size >= 39) {
|
||||
lag = 5;
|
||||
} else {
|
||||
lag = 3;
|
||||
}
|
||||
mid = (size - lag) / 2;
|
||||
|
||||
memset(sfmt, 0x8b, sizeof(sfmt_t));
|
||||
if (key_length + 1 > SFMT_N32) {
|
||||
count = key_length + 1;
|
||||
} else {
|
||||
count = SFMT_N32;
|
||||
}
|
||||
r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)]
|
||||
^ psfmt32[idxof(SFMT_N32 - 1)]);
|
||||
psfmt32[idxof(mid)] += r;
|
||||
r += key_length;
|
||||
psfmt32[idxof(mid + lag)] += r;
|
||||
psfmt32[idxof(0)] = r;
|
||||
|
||||
count--;
|
||||
for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
|
||||
r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % SFMT_N32)]
|
||||
^ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
|
||||
psfmt32[idxof((i + mid) % SFMT_N32)] += r;
|
||||
r += init_key[j] + i;
|
||||
psfmt32[idxof((i + mid + lag) % SFMT_N32)] += r;
|
||||
psfmt32[idxof(i)] = r;
|
||||
i = (i + 1) % SFMT_N32;
|
||||
}
|
||||
for (; j < count; j++) {
|
||||
r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % SFMT_N32)]
|
||||
^ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
|
||||
psfmt32[idxof((i + mid) % SFMT_N32)] += r;
|
||||
r += i;
|
||||
psfmt32[idxof((i + mid + lag) % SFMT_N32)] += r;
|
||||
psfmt32[idxof(i)] = r;
|
||||
i = (i + 1) % SFMT_N32;
|
||||
}
|
||||
for (j = 0; j < SFMT_N32; j++) {
|
||||
r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % SFMT_N32)]
|
||||
+ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
|
||||
psfmt32[idxof((i + mid) % SFMT_N32)] ^= r;
|
||||
r -= i;
|
||||
psfmt32[idxof((i + mid + lag) % SFMT_N32)] ^= r;
|
||||
psfmt32[idxof(i)] = r;
|
||||
i = (i + 1) % SFMT_N32;
|
||||
}
|
||||
|
||||
sfmt->idx = SFMT_N32;
|
||||
period_certification(sfmt);
|
||||
}
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue