added random number generation algorithms

This commit is contained in:
timerix 2022-10-24 03:29:42 +06:00
parent 0e6a0f6482
commit f33804f5b8
20 changed files with 810 additions and 3 deletions

View File

@ -13,6 +13,7 @@ char* errname(ErrorId err){
case ERR_ENDOFSTR: return "ERR_ENDOFSTR"; case ERR_ENDOFSTR: return "ERR_ENDOFSTR";
case ERR_KEYNOTFOUND: return "ERR_KEYNOTFOUND"; case ERR_KEYNOTFOUND: return "ERR_KEYNOTFOUND";
case ERR_FORMAT: return "ERR_FORMAT"; case ERR_FORMAT: return "ERR_FORMAT";
case ERR_UNEXPECTEDVAL: return "ERR_UNEXPECTEDVAL";
default: return "UNKNOWN_ERROR"; default: return "UNKNOWN_ERROR";
} }
} }

View File

@ -11,7 +11,7 @@ typedef enum ErrorId {
SUCCESS, // not an error SUCCESS, // not an error
ERR_MAXLENGTH, ERR_WRONGTYPE, ERR_WRONGINDEX, ERR_MAXLENGTH, ERR_WRONGTYPE, ERR_WRONGINDEX,
ERR_NOTIMPLEMENTED, ERR_NULLPTR, ERR_ENDOFSTR, ERR_NOTIMPLEMENTED, ERR_NULLPTR, ERR_ENDOFSTR,
ERR_KEYNOTFOUND, ERR_FORMAT ERR_KEYNOTFOUND, ERR_FORMAT, ERR_UNEXPECTEDVAL
} ErrorId; } ErrorId;
char* errname(ErrorId err); char* errname(ErrorId err);

6
src/random/krandom.c Normal file
View File

@ -0,0 +1,6 @@
#include "krandom.h"
bool fate(float chance){
int limit=1/chance + 0.01f;
return rand()%limit == 0;
}

91
src/random/krandom.h Normal file
View File

@ -0,0 +1,91 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../base/std.h"
/*
You can choose any algorithm that has required functions:
some_alg64_state some_alg64_init(uint64 seed);
uint64 some_alg64_next(some_alg64_state);
#define KRAND_ALG64 some_alg64
#include "kerep/random/krandom.h"
The same way it works for 32-bit RNGs:
some_alg64_state some_alg32_init(uint32 seed);
uint32 some_alg32_next(some_alg64_state);
#define KRAND_ALG32 some_alg32
#include "kerep/random/krandom.h"
*/
// default rng_next function
#ifndef KRAND_ALG32
#define KRAND_ALG32 xoroshiro128plus
#endif
#ifndef KRAND_ALG64
#define KRAND_ALG64 xoshiro128plus
#endif
typedef void* KRAND_ALG32_state;
typedef void* KRAND_ALG64_state;
#define KRAND_ALG32_next(STATE) xoshiro128plus##_next(STATE)
#define KRAND_ALG32_init(SEED) xoshiro128plus##_init(SEED)
#define KRAND_ALG32_initFromTime() xoshiro128plus##_initFromTime()
#define KRAND_ALG64_next(STATE) xoshiro256plus##_next(STATE)
#define KRAND_ALG64_init(SEED) xoshiro256plus##_init(SEED)
#define KRAND_ALG64_initFromTime() xoshiro256plus##_initFromTime()
#define __krand_declare_alg(ALG, VALUE_SIZE)\
typedef void* ALG##_state;\
ALG##_state ALG##_init(uint64 seed);\
static inline ALG##_state ALG##_initFromTime(void) { return ALG##_init(time(NULL)); }\
uint##VALUE_SIZE ALG##_next(ALG##_state);
// different algorithm declarations
// for ALG32
// xoroshiro64
__krand_declare_alg(xoroshiro64star, 32)
__krand_declare_alg(xoroshiro64starstar, 32)
// xoshiro128
__krand_declare_alg(xoshiro128plus, 32)
__krand_declare_alg(xoshiro128plusplus, 32)
__krand_declare_alg(xoshiro128starstar, 32)
// for ALG64
// xoroshiro128
__krand_declare_alg(xoroshiro128plus, 64)
__krand_declare_alg(xoroshiro128plusplus, 64)
__krand_declare_alg(xoroshiro128starstar, 64)
// xoshiro256
__krand_declare_alg(xoshiro256plus, 64)
__krand_declare_alg(xoshiro256plusplus, 64)
__krand_declare_alg(xoshiro256starstar, 64)
// splitmix64
__krand_declare_alg(splitmix64, 64)
#define __krand_next_definition(VALUE_SIZE) { return from+KRAND_ALG##VALUE_SIZE##_next(state)%(to-from); }
// ready-to-use functions
static inline int8 krand_next8 (KRAND_ALG32_state state, int8 from, int8 to) __krand_next_definition(32)
static inline int16 krand_next16(KRAND_ALG32_state state, int16 from, int16 to) __krand_next_definition(32)
static inline int32 krand_next32(KRAND_ALG32_state state, int32 from, int32 to) __krand_next_definition(32)
static inline int64 krand_next64(KRAND_ALG64_state state, int64 from, int64 to) __krand_next_definition(64)
// divides random number by 2^64 to return a value between 0 and 1
static inline float32 krand_nextFloat32(KRAND_ALG32_state state) {return (uint32)KRAND_ALG32_next(state)/0xffffffff; }
static inline float64 krand_nextFloat64(KRAND_ALG64_state state) {return KRAND_ALG64_next(state)/0xffffffff; }
///@param chance (0-1.0) is probability of success
bool fate(float chance);
#if __cplusplus
}
#endif

35
src/random/splitmix64.c Normal file
View File

@ -0,0 +1,35 @@
#include "krandom.h"
/*
This is a fixed-increment version of Java 8's SplittableRandom generator
See http://dx.doi.org/10.1145/2714064.2660195 and
http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
It is a very fast generator passing BigCrush, and it can be useful if
for some reason you absolutely want 64 bits of state; otherwise, we
rather suggest to use a xoroshiro128+ (for moderately parallel
computations) or xorshift1024* (for massively parallel computations)
generator.
*/
// The state can be seeded with any (upto) 64 bit integer value.
typedef uint64 _state_t;
void* splitmix64_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
*state=seed;
return state;
}
uint64 splitmix64_next(void* _state) {
_state_t* state=_state;
// increment the state variable
*state += 0x9e3779b97f4a7c15;
// copy the state to a working variable
uint64 z = *state;
// xor the variable with the variable right bit shifted 30 then multiply by a constant
z = (z ^ (z>>30)) * 0xbf58476d1ce4e5b9;
// xor the variable with the variable right bit shifted 27 then multiply by a constant
z = (z ^ (z>>27)) * 0x94d049bb133111eb;
// return the variable xored with itself right bit shifted 31
return z ^ (z>>31);
}

View File

@ -0,0 +1,53 @@
/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/*
This is xoroshiro64* 1.0, our best and fastest 32-bit small-state
generator for 32-bit floating-point numbers. We suggest to use its
upper bits for floating-point generation, as it is slightly faster than
xoroshiro64**. It passes all tests we are aware of except for linearity
tests, as the lowest six bits have low linear complexity, so if low
linear complexity is not considered an issue (as it is usually the
case) it can be used to generate 32-bit outputs, too.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero.
*/
static inline uint32 rotl(const uint32 x, int k) {
return (x << k) | (x >> (32 - k));
}
typedef union {
uint64 merged;
uint32 s[2];
} _state_t;
uint32 xoroshiro64star_next(void* _state) {
_state_t* state=_state;
const uint32 s0 = state->s[0];
uint32 s1 = state->s[1];
const uint32 result = s0 * 0x9E3779BB;
s1 ^= s0;
state->s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
state->s[1] = rotl(s1, 13); // c
return result;
}
void* xoroshiro64star_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->merged=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,49 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoroshiro64** 1.0, our 32-bit all-purpose, rock-solid,
small-state generator. It is extremely fast and it passes all tests we
are aware of, but its state space is not large enough for any parallel
application.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoroshiro64* is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline uint32 rotl(const uint32 x, int k) {
return (x << k) | (x >> (32 - k));
}
typedef union {
uint64 merged;
uint32 s[2];
} _state_t;
uint32 xoroshiro64starstar_next(void* _state) {
_state_t* state=_state;
const uint32 s0 = state->s[0];
uint32 s1 = state->s[1];
const uint32 result = rotl(s0 * 0x9E3779BB, 5) * 5;
s1 ^= s0;
state->s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
state->s[1] = rotl(s1, 13); // c
return result;
}
void* xoroshiro64starstar_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->merged=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,62 @@
/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoroshiro128+ 1.0, our best and fastest small-state generator
for floating-point numbers, but its state space is large enough only
for mild parallelism. We suggest to use its upper bits for
floating-point generation, as it is slightly faster than
xoroshiro128++/xoroshiro128**. It passes all tests we are aware of
except for the four lower bits, which might fail linearity tests (and
just those), so if low linear complexity is not considered an issue (as
it is usually the case) it can be used to generate 64-bit outputs, too;
moreover, this generator has a very mild Hamming-weight dependency
making our test (http://prng.di.unimi.it/hwd.php) fail after 5 TB of
output; we believe this slight bias cannot affect any application. If
you are concerned, use xoroshiro128++, xoroshiro128** or xoshiro256+.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s.
NOTE: the parameters (a=24, b=16, b=37) of this version give slightly
better results in our test than the 2016 version (a=55, b=14, c=36).
*/
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x >> (64 - k));
}
typedef union {
uint32 s[2];
} _state_t;
uint64 xoroshiro128plus_next(void* _state){
_state_t* state=_state;
const uint64 s0 = state->s[0];
uint64 s1 = state->s[1];
const uint64 result = s0 + s1;
s1 ^= s0;
state->s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
state->s[1] = rotl(s1, 37); // c
return result;
}
void* xoroshiro128plus_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,51 @@
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoroshiro128++ 1.0, one of our all-purpose, rock-solid,
small-state generators. It is extremely (sub-ns) fast and it passes all
tests we are aware of, but its state space is large enough only for
mild parallelism.
For generating just floating-point numbers, xoroshiro128+ is even
faster (but it has a very mild bias, see notes in the comments).
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x >> (64 - k));
}
typedef union {
uint32 s[2];
} _state_t;
uint64 xoroshiro128plusplus_next(void* _state){
_state_t* state=_state;
const uint64 s0 = state->s[0];
uint64 s1 = state->s[1];
const uint64 result = rotl(s0 + s1, 17) + s0;
s1 ^= s0;
state->s[0] = rotl(s0, 49) ^ s1 ^ (s1 << 21); // a, b
state->s[1] = rotl(s1, 28); // c
return result;
}
void* xoroshiro128plusplus_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,51 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoroshiro128** 1.0, one of our all-purpose, rock-solid,
small-state generators. It is extremely (sub-ns) fast and it passes all
tests we are aware of, but its state space is large enough only for
mild parallelism.
For generating just floating-point numbers, xoroshiro128+ is even
faster (but it has a very mild bias, see notes in the comments).
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x >> (64 - k));
}
typedef union {
uint32 s[2];
} _state_t;
uint64 xoroshiro128starstar_next(void* _state){
_state_t* state=_state;
const uint64 s0 = state->s[0];
uint64 s1 = state->s[1];
const uint64 result = rotl(s0 * 5, 7) * 9;
s1 ^= s0;
state->s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
state->s[1] = rotl(s1, 37); // c
return result;
}
void* xoroshiro128starstar_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,24 @@
# Xoshiro/Xoroshiro RNG algorithms
There are a bunch of versions of xoshiro/xoroshiro algorithms, which are created by [David Blackman and Sebastiano Vigna](https://prng.di.unimi.it/)
```
xoroshiro
├── 32bitValue
| ├── xoroshiro64star.c
| └── xoroshiro64starstar.c
└── 64bitValue
├── xoroshiro128plus.c
├── xoroshiro128plusplus.c
└── xoroshiro128starstar.c
xoshiro
├── 32bitValue
│ ├── xoshiro128plus.c
│ ├── xoshiro128plusplus.c
│ └── xoshiro128starstar.c
└── 64bitValue
├── xoshiro256plus.c
├── xoshiro256plusplus.c
└── xoshiro256starstar.c
```

View File

@ -0,0 +1,58 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoshiro128+ 1.0, our best and fastest 32-bit generator for 32-bit
floating-point numbers. We suggest to use its upper bits for
floating-point generation, as it is slightly faster than xoshiro128**.
It passes all tests we are aware of except for
linearity tests, as the lowest four bits have low linear complexity, so
if low linear complexity is not considered an issue (as it is usually
the case) it can be used to generate 32-bit outputs, too.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. */
static inline uint32 rotl(const uint32 x, int k) {
return (x << k) | (x >> (32 - k));
}
typedef union {
uint64 merged[2];
uint32 s[4];
} _state_t;
uint32 xoshiro128plus_next(void* _state){
_state_t* state=_state;
const uint32 result = state->s[0] + state->s[3];
const uint32 t = state->s[1] << 9;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 11);
return result;
}
void* xoshiro128plus_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->merged[0]=splitmix64_next(splitmix);
state->merged[1]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,55 @@
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
generators. It has excellent speed, a state size (128 bits) that is
large enough for mild parallelism, and it passes all tests we are aware
of.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoshiro128+ is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline uint32 rotl(const uint32 x, int k) {
return (x << k) | (x >> (32 - k));
}
typedef union {
uint64 merged[2];
uint32 s[4];
} _state_t;
uint32 xoshiro128plusplus_next(void* _state){
_state_t* state=_state;
const uint32 result = rotl(state->s[0] + state->s[3], 7) + state->s[0];
const uint32 t = state->s[1] << 9;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 11);
return result;
}
void* xoshiro128plusplus_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->merged[0]=splitmix64_next(splitmix);
state->merged[1]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,58 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
generators. It has excellent speed, a state size (128 bits) that is
large enough for mild parallelism, and it passes all tests we are aware
of.
Note that version 1.0 had mistakenly state->s[0] instead of state->s[1] as state
word passed to the scrambler.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoshiro128+ is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline uint32 rotl(const uint32 x, int k) {
return (x << k) | (x >> (32 - k));
}
typedef union {
uint64 merged[2];
uint32 s[4];
} _state_t;
uint32 xoshiro128starstar_next(void* _state){
_state_t* state=_state;
const uint32 result = rotl(state->s[1] * 5, 7) * 9;
const uint32 t = state->s[1] << 9;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 11);
return result;
}
void* xoshiro128starstar_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->merged[0]=splitmix64_next(splitmix);
state->merged[1]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,61 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoshiro256+ 1.0, our best and fastest generator for floating-point
numbers. We suggest to use its upper bits for floating-point
generation, as it is slightly faster than xoshiro256++/xoshiro256**. It
passes all tests we are aware of except for the lowest three bits,
which might fail linearity tests (and just those), so if low linear
complexity is not considered an issue (as it is usually the case) it
can be used to generate 64-bit outputs, too.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x >> (64 - k));
}
typedef union {
uint64 s[4];
} _state_t;
uint64 xoshiro256plus_next(void* _state){
_state_t* state=_state;
const uint64 result = state->s[0] + state->s[3];
const uint64 t = state->s[1] << 17;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 45);
return result;
}
void* xoshiro256plus_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
state->s[2]=splitmix64_next(splitmix);
state->s[3]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,51 @@
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
It has excellent (sub-ns) speed, a state (256 bits) that is large
enough for any parallel application, and it passes all tests we are
aware of.
For generating just floating-point numbers, xoshiro256+ is even faster.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x>>(64 - k));
}
typedef union {
uint64 s[4];
} _state_t;
uint64 xoshiro256plusplus_next(void* _state) {
_state_t* state=_state;
const uint64 result=rotl(state->s[0] + state->s[3], 23) + state->s[0];
const uint64 t=state->s[1] << 17;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3]=rotl(state->s[3], 45);
return result;
}
void* xoshiro256plusplus_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
state->s[2]=splitmix64_next(splitmix);
state->s[3]=splitmix64_next(splitmix);
return state;
}

View File

@ -0,0 +1,56 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "../../krandom.h"
/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
generators. It has excellent (sub-ns) speed, a state (256 bits) that is
large enough for any parallel application, and it passes all tests we
are aware of.
For generating just floating-point numbers, xoshiro256+ is even faster.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x >> (64 - k));
}
typedef union {
uint64 s[4];
} _state_t;
uint64 xoshiro256starstar_next(void* _state){
_state_t* state=_state;
const uint64 result = rotl(state->s[1] * 5, 7) * 9;
const uint64 t = state->s[1] << 17;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 45);
return result;
}
void* xoshiro256starstar_init(uint64 seed){
_state_t* state=malloc(sizeof(_state_t));
splitmix64_state splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
state->s[2]=splitmix64_next(splitmix);
state->s[3]=splitmix64_next(splitmix);
return state;
}

View File

@ -10,9 +10,9 @@ void test_all(){
test_hashtable(); test_hashtable();
test_dtsod(); test_dtsod();
test_kprint_colors(); test_kprint_colors();
test_rng_algorithms();
printf("\e[96m--------------------------------------\e[0m\n"); printf("\e[96m--------------------------------------\e[0m\n");
} }
int main(){ int main(){
setlocale(LC_ALL, "en-US.Unicode"); setlocale(LC_ALL, "en-US.Unicode");
ktDescriptors_beginInit(); ktDescriptors_beginInit();
@ -20,7 +20,8 @@ int main(){
ktDescriptors_endInit(); ktDescriptors_endInit();
printf("\e[97mkerep tests are starting!\n"); printf("\e[97mkerep tests are starting!\n");
// optime("test_all",1,test_all()); // optime("test_all",1,test_all());
test_kprint_colors(); // test_kprint_colors();
test_rng_algorithms();
printf("\e[0m\n"); printf("\e[0m\n");
return 0; return 0;
} }

View File

@ -0,0 +1,43 @@
#include "tests.h"
#include "../src/random/krandom.h"
#define test_alg(ALG, VALUE_SIZE, EXPECTED_FROM_ZERO){\
printf("\e[94mrng algorithm: \e[96m" #ALG "\n");\
ALG##_state s= ALG##_init(0);\
uint##VALUE_SIZE r=ALG##_next(s);\
printf("\e[97m next from zero seed:");\
if(r!=EXPECTED_FROM_ZERO){\
printf("\e[91m %llu\n", (uint64)r);\
throw(ERR_UNEXPECTEDVAL);\
}\
printf("\e[92m %llu\n", (uint64)r);\
s= ALG##_initFromTime();\
r=ALG##_next(s);\
printf("\e[97m next from time seed:\e[92m %llu\n", (uint64)r);\
}
void test_rng_algorithms(){
optime("test_rng_algorithms",1,({
printf("\e[96m--------[test_rng_algorithms]---------\n");
// for ALG32
// xoroshiro64
test_alg(xoroshiro64star, 32, 932574677ULL)
test_alg(xoroshiro64starstar, 32, 3183060286ULL)
// xoshiro128
test_alg(xoshiro128plus, 32, 3918949401ULL)
test_alg(xoshiro128plusplus, 32, 1179900579ULL)
test_alg(xoshiro128starstar, 32, 3737715805ULL)
// for ALG64
// xoroshiro128
test_alg(xoroshiro128plus, 64, 4778832803ULL)
test_alg(xoroshiro128plusplus, 64, 626373238705583ULL)
test_alg(xoroshiro128starstar, 64, 11897572417920ULL)
// xoshiro256
test_alg(xoshiro256plus, 64, 15757075719729598363ULL)
test_alg(xoshiro256plusplus, 64, 5987356902031041503ULL)
test_alg(xoshiro256starstar, 64, 11091344671253066420ULL)
// splitmix64
test_alg(splitmix64, 64, 16294208416658607535ULL)
}));
}

View File

@ -15,6 +15,7 @@ void test_hashtable();
void test_dtsod(); void test_dtsod();
void test_kprint_colors(); void test_kprint_colors();
void test_autoarrVsVector(); void test_autoarrVsVector();
void test_rng_algorithms();
#define PRINT_SIZEOF(T) printf("\e[94m" #T " size: \e[96m" IFWIN("%llu", "%lu") "\n", sizeof(T)) #define PRINT_SIZEOF(T) printf("\e[94m" #T " size: \e[96m" IFWIN("%llu", "%lu") "\n", sizeof(T))