added random number generation algorithms
This commit is contained in:
parent
0e6a0f6482
commit
f33804f5b8
@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
6
src/random/krandom.c
Normal 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
91
src/random/krandom.h
Normal 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
35
src/random/splitmix64.c
Normal 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);
|
||||||
|
}
|
||||||
53
src/random/xoroshiro/32bitValue/xoroshiro64star.c
Normal file
53
src/random/xoroshiro/32bitValue/xoroshiro64star.c
Normal 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;
|
||||||
|
}
|
||||||
49
src/random/xoroshiro/32bitValue/xoroshiro64starstar.c
Normal file
49
src/random/xoroshiro/32bitValue/xoroshiro64starstar.c
Normal 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;
|
||||||
|
}
|
||||||
62
src/random/xoroshiro/64bitValue/xoroshiro128plus.c
Normal file
62
src/random/xoroshiro/64bitValue/xoroshiro128plus.c
Normal 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;
|
||||||
|
}
|
||||||
51
src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c
Normal file
51
src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c
Normal 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;
|
||||||
|
}
|
||||||
51
src/random/xoroshiro/64bitValue/xoroshiro128starstar.c
Normal file
51
src/random/xoroshiro/64bitValue/xoroshiro128starstar.c
Normal 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;
|
||||||
|
}
|
||||||
24
src/random/xoshiro-xoroshiro.md
Normal file
24
src/random/xoshiro-xoroshiro.md
Normal 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
|
||||||
|
```
|
||||||
58
src/random/xoshiro/32bitValue/xoshiro128plus.c
Normal file
58
src/random/xoshiro/32bitValue/xoshiro128plus.c
Normal 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;
|
||||||
|
}
|
||||||
55
src/random/xoshiro/32bitValue/xoshiro128plusplus.c
Normal file
55
src/random/xoshiro/32bitValue/xoshiro128plusplus.c
Normal 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;
|
||||||
|
}
|
||||||
58
src/random/xoshiro/32bitValue/xoshiro128starstar.c
Normal file
58
src/random/xoshiro/32bitValue/xoshiro128starstar.c
Normal 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;
|
||||||
|
}
|
||||||
61
src/random/xoshiro/64bitValue/xoshiro256plus.c
Normal file
61
src/random/xoshiro/64bitValue/xoshiro256plus.c
Normal 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;
|
||||||
|
}
|
||||||
51
src/random/xoshiro/64bitValue/xoshiro256plusplus.c
Normal file
51
src/random/xoshiro/64bitValue/xoshiro256plusplus.c
Normal 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;
|
||||||
|
}
|
||||||
56
src/random/xoshiro/64bitValue/xoshiro256starstar.c
Normal file
56
src/random/xoshiro/64bitValue/xoshiro256starstar.c
Normal 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;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
43
tests/test_rng_algorithms.c
Normal file
43
tests/test_rng_algorithms.c
Normal 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)
|
||||||
|
}));
|
||||||
|
}
|
||||||
@ -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))
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user