diff --git a/src/base/errors.c b/src/base/errors.c index 5adc0ee..4d0d2be 100644 --- a/src/base/errors.c +++ b/src/base/errors.c @@ -13,6 +13,7 @@ char* errname(ErrorId err){ case ERR_ENDOFSTR: return "ERR_ENDOFSTR"; case ERR_KEYNOTFOUND: return "ERR_KEYNOTFOUND"; case ERR_FORMAT: return "ERR_FORMAT"; + case ERR_UNEXPECTEDVAL: return "ERR_UNEXPECTEDVAL"; default: return "UNKNOWN_ERROR"; } } diff --git a/src/base/errors.h b/src/base/errors.h index 7be9aa9..4abc7df 100644 --- a/src/base/errors.h +++ b/src/base/errors.h @@ -11,7 +11,7 @@ typedef enum ErrorId { SUCCESS, // not an error ERR_MAXLENGTH, ERR_WRONGTYPE, ERR_WRONGINDEX, ERR_NOTIMPLEMENTED, ERR_NULLPTR, ERR_ENDOFSTR, - ERR_KEYNOTFOUND, ERR_FORMAT + ERR_KEYNOTFOUND, ERR_FORMAT, ERR_UNEXPECTEDVAL } ErrorId; char* errname(ErrorId err); diff --git a/src/random/krandom.c b/src/random/krandom.c new file mode 100644 index 0000000..3801717 --- /dev/null +++ b/src/random/krandom.c @@ -0,0 +1,6 @@ +#include "krandom.h" + +bool fate(float chance){ + int limit=1/chance + 0.01f; + return rand()%limit == 0; +} diff --git a/src/random/krandom.h b/src/random/krandom.h new file mode 100644 index 0000000..4815468 --- /dev/null +++ b/src/random/krandom.h @@ -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 \ No newline at end of file diff --git a/src/random/splitmix64.c b/src/random/splitmix64.c new file mode 100644 index 0000000..cb89ed4 --- /dev/null +++ b/src/random/splitmix64.c @@ -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); +} diff --git a/src/random/xoroshiro/32bitValue/xoroshiro64star.c b/src/random/xoroshiro/32bitValue/xoroshiro64star.c new file mode 100644 index 0000000..89bb6cc --- /dev/null +++ b/src/random/xoroshiro/32bitValue/xoroshiro64star.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoroshiro/32bitValue/xoroshiro64starstar.c b/src/random/xoroshiro/32bitValue/xoroshiro64starstar.c new file mode 100644 index 0000000..6edcd59 --- /dev/null +++ b/src/random/xoroshiro/32bitValue/xoroshiro64starstar.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoroshiro/64bitValue/xoroshiro128plus.c b/src/random/xoroshiro/64bitValue/xoroshiro128plus.c new file mode 100644 index 0000000..cf70f65 --- /dev/null +++ b/src/random/xoroshiro/64bitValue/xoroshiro128plus.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c b/src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c new file mode 100644 index 0000000..aaf384d --- /dev/null +++ b/src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoroshiro/64bitValue/xoroshiro128starstar.c b/src/random/xoroshiro/64bitValue/xoroshiro128starstar.c new file mode 100644 index 0000000..d811ab6 --- /dev/null +++ b/src/random/xoroshiro/64bitValue/xoroshiro128starstar.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoshiro-xoroshiro.md b/src/random/xoshiro-xoroshiro.md new file mode 100644 index 0000000..269477c --- /dev/null +++ b/src/random/xoshiro-xoroshiro.md @@ -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 +``` diff --git a/src/random/xoshiro/32bitValue/xoshiro128plus.c b/src/random/xoshiro/32bitValue/xoshiro128plus.c new file mode 100644 index 0000000..28c90ad --- /dev/null +++ b/src/random/xoshiro/32bitValue/xoshiro128plus.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoshiro/32bitValue/xoshiro128plusplus.c b/src/random/xoshiro/32bitValue/xoshiro128plusplus.c new file mode 100644 index 0000000..689dc06 --- /dev/null +++ b/src/random/xoshiro/32bitValue/xoshiro128plusplus.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoshiro/32bitValue/xoshiro128starstar.c b/src/random/xoshiro/32bitValue/xoshiro128starstar.c new file mode 100644 index 0000000..bf458fe --- /dev/null +++ b/src/random/xoshiro/32bitValue/xoshiro128starstar.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoshiro/64bitValue/xoshiro256plus.c b/src/random/xoshiro/64bitValue/xoshiro256plus.c new file mode 100644 index 0000000..e6829d4 --- /dev/null +++ b/src/random/xoshiro/64bitValue/xoshiro256plus.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoshiro/64bitValue/xoshiro256plusplus.c b/src/random/xoshiro/64bitValue/xoshiro256plusplus.c new file mode 100644 index 0000000..042035c --- /dev/null +++ b/src/random/xoshiro/64bitValue/xoshiro256plusplus.c @@ -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 . */ + +#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; +} diff --git a/src/random/xoshiro/64bitValue/xoshiro256starstar.c b/src/random/xoshiro/64bitValue/xoshiro256starstar.c new file mode 100644 index 0000000..625aedb --- /dev/null +++ b/src/random/xoshiro/64bitValue/xoshiro256starstar.c @@ -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 . */ + +#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; +} diff --git a/tests/main.cpp b/tests/main.cpp index 35967c1..0ba2387 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -10,9 +10,9 @@ void test_all(){ test_hashtable(); test_dtsod(); test_kprint_colors(); + test_rng_algorithms(); printf("\e[96m--------------------------------------\e[0m\n"); } - int main(){ setlocale(LC_ALL, "en-US.Unicode"); ktDescriptors_beginInit(); @@ -20,7 +20,8 @@ int main(){ ktDescriptors_endInit(); printf("\e[97mkerep tests are starting!\n"); // optime("test_all",1,test_all()); - test_kprint_colors(); + // test_kprint_colors(); + test_rng_algorithms(); printf("\e[0m\n"); return 0; } diff --git a/tests/test_rng_algorithms.c b/tests/test_rng_algorithms.c new file mode 100644 index 0000000..250def8 --- /dev/null +++ b/tests/test_rng_algorithms.c @@ -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) + })); +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index 584d8c4..db46e93 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -15,6 +15,7 @@ void test_hashtable(); void test_dtsod(); void test_kprint_colors(); void test_autoarrVsVector(); +void test_rng_algorithms(); #define PRINT_SIZEOF(T) printf("\e[94m" #T " size: \e[96m" IFWIN("%llu", "%lu") "\n", sizeof(T))