Added xorshift generator and longest runs test
This commit is contained in:
parent
85196b5d84
commit
7719660bac
16
rng/rng/.vscode/c_cpp_properties.json
vendored
Normal file
16
rng/rng/.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++20",
|
||||
"intelliSenseMode": "macos-clang-arm64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
63
rng/rng/.vscode/settings.json
vendored
63
rng/rng/.vscode/settings.json
vendored
@ -1,63 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.ts": "typescriptreact",
|
||||
"array": "cpp",
|
||||
"iostream": "cpp",
|
||||
"__bit_reference": "cpp",
|
||||
"__hash_table": "cpp",
|
||||
"__locale": "cpp",
|
||||
"__node_handle": "cpp",
|
||||
"__split_buffer": "cpp",
|
||||
"__threading_support": "cpp",
|
||||
"__verbose_abort": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"complex": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"execution": "cpp",
|
||||
"memory": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"ios": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"locale": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"optional": "cpp",
|
||||
"ostream": "cpp",
|
||||
"print": "cpp",
|
||||
"queue": "cpp",
|
||||
"ratio": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stack": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"tuple": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"variant": "cpp",
|
||||
"vector": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"__tree": "cpp",
|
||||
"csignal": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"unordered_set": "cpp"
|
||||
}
|
||||
}
|
@ -6,38 +6,26 @@
|
||||
//
|
||||
|
||||
#include "../../rng.h"
|
||||
#include "../generator.h"
|
||||
|
||||
// parameters recommended by Nakazawa & Nakazawa
|
||||
// https://en.wikipedia.org/wiki/Lehmer_random_number_generator
|
||||
|
||||
uint64_t lehmer_minstd(uint64_t prev){
|
||||
uint64_t a = 7759097958782935LL;
|
||||
uint64_t m = 18055400005099021LL;
|
||||
|
||||
uint64_t result = (a * prev) % m;
|
||||
|
||||
return result;
|
||||
namespace splat {
|
||||
class lehmer_generator : public PRNG {
|
||||
public:
|
||||
lehmer_generator(uint32_t genSeed) : PRNG(genSeed) {
|
||||
seed = genSeed;
|
||||
}
|
||||
uint32_t generate() override {
|
||||
seed = (a * seed) % m;
|
||||
return seed >> 32;
|
||||
}
|
||||
std::string getName() override {
|
||||
return "lehmer";
|
||||
}
|
||||
private:
|
||||
uint64_t a = 7759097958782935LL;
|
||||
uint64_t m = 18055400005099021LL;
|
||||
};
|
||||
}
|
||||
|
||||
class lehmer_generator {
|
||||
uint64_t seed;
|
||||
public:
|
||||
uint32_t generate(){
|
||||
seed = lehmer_minstd(seed);
|
||||
return seed;
|
||||
}
|
||||
lehmer_generator(uint64_t genSeed){
|
||||
seed = genSeed;
|
||||
}
|
||||
};
|
||||
|
||||
// std::vector<std::bitset<32>> lehmer_generate(int seed, int amount){
|
||||
// std::vector<std::bitset<32>> bits(amount);
|
||||
|
||||
// for(int i=0; i<amount; i++){
|
||||
// seed = lehmer_minstd(seed);
|
||||
// bits[i]=seed;
|
||||
// }
|
||||
|
||||
// return bits;
|
||||
// }
|
18
rng/rng/generators/generator.h
Normal file
18
rng/rng/generators/generator.h
Normal file
@ -0,0 +1,18 @@
|
||||
#include "../rng.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace splat {
|
||||
class PRNG {
|
||||
public:
|
||||
virtual uint32_t generate() {return -1;};
|
||||
virtual ~PRNG() = default;
|
||||
virtual std::string getName() {return "N/A";};
|
||||
PRNG(uint32_t genseed){
|
||||
seed = genseed;
|
||||
}
|
||||
protected:
|
||||
uint32_t seed;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "../rng.h"
|
||||
#include "./generator.h"
|
||||
|
||||
// more specifically this will be mt19937 - 32 bit
|
||||
|
||||
@ -63,33 +64,33 @@ std::array<uint32_t,624> mt19937_temper(std::array<uint32_t,624> state){
|
||||
return tempered;
|
||||
}
|
||||
|
||||
class mt19937_generator {
|
||||
public:
|
||||
uint32_t seed;
|
||||
uint32_t generate() {
|
||||
uint32_t generated = random_values[position];
|
||||
position++;
|
||||
if(position>=624){
|
||||
namespace splat {
|
||||
class mt19937_generator : public PRNG {
|
||||
public:
|
||||
mt19937_generator(uint32_t genSeed) : PRNG(genSeed) {
|
||||
state = mt19937_init(seed);
|
||||
nextblock();
|
||||
}
|
||||
return generated;
|
||||
}
|
||||
double generate_01(){
|
||||
return ((double)generate())/(4294967295);
|
||||
}
|
||||
mt19937_generator(uint32_t genSeed){
|
||||
seed = genSeed;
|
||||
state = mt19937_init(seed);
|
||||
nextblock();
|
||||
}
|
||||
private:
|
||||
std::array<uint32_t,624> state;
|
||||
std::array<uint32_t,624> random_values;
|
||||
int position;
|
||||
// goes to next block of 624 values
|
||||
void nextblock() {
|
||||
state = mt19937_twist(state);
|
||||
random_values = mt19937_temper(state);
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
uint32_t generate() override {
|
||||
uint32_t generated = random_values[position];
|
||||
position++;
|
||||
if(position>=624){
|
||||
nextblock();
|
||||
}
|
||||
return generated;
|
||||
}
|
||||
std::string getName() override {
|
||||
return "mt19937-32";
|
||||
}
|
||||
private:
|
||||
std::array<uint32_t,624> state;
|
||||
std::array<uint32_t,624> random_values;
|
||||
int position;
|
||||
// goes to next block of 624 values
|
||||
void nextblock() {
|
||||
state = mt19937_twist(state);
|
||||
random_values = mt19937_temper(state);
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
}
|
25
rng/rng/generators/xorshift.cpp
Normal file
25
rng/rng/generators/xorshift.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "../rng.h"
|
||||
#include "./generator.h"
|
||||
|
||||
// parameters recommended by Nakazawa & Nakazawa
|
||||
// https://en.wikipedia.org/wiki/Lehmer_random_number_generator
|
||||
|
||||
namespace splat {
|
||||
class xorshift32 : public PRNG {
|
||||
public:
|
||||
xorshift32(uint32_t genSeed) : PRNG(genSeed) {
|
||||
state = genSeed;
|
||||
}
|
||||
uint32_t generate() override {
|
||||
state ^= state << 13;
|
||||
state ^= state >> 17;
|
||||
state ^= state << 5;
|
||||
return state;
|
||||
}
|
||||
std::string getName() override {
|
||||
return "xorshift32";
|
||||
}
|
||||
private:
|
||||
uint32_t state;
|
||||
};
|
||||
}
|
@ -8,45 +8,78 @@
|
||||
#include "rng.h"
|
||||
#include "generators/LCG/lehmer.cpp"
|
||||
#include "generators/mt19937.cpp"
|
||||
#include "generators/xorshift.cpp"
|
||||
#include "randomness_tests/frequency_monobit.cpp"
|
||||
#include "randomness_tests/frequency_block.cpp"
|
||||
#include "randomness_tests/runs.cpp"
|
||||
#include "randomness_tests/runs_ones.cpp"
|
||||
|
||||
|
||||
|
||||
#include "generators/generator.h"
|
||||
#include "randomness_tests/rngtest.h"
|
||||
|
||||
namespace splat {
|
||||
template <typename T>
|
||||
void addGen(std::vector<std::unique_ptr<PRNG>> &generators, uint32_t &seed){
|
||||
generators.push_back(std::make_unique<T>(seed));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<PRNG>> getAllGenerators(uint32_t seed){
|
||||
std::vector<std::unique_ptr<PRNG>> generators;
|
||||
|
||||
// add generators here
|
||||
addGen<mt19937_generator>(generators, seed);
|
||||
addGen<lehmer_generator>(generators, seed);
|
||||
addGen<xorshift32>(generators,seed);
|
||||
|
||||
return generators;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void addTest(std::vector<std::unique_ptr<RNGTEST>> &tests, std::vector<std::bitset<32>> &data){
|
||||
tests.push_back(std::make_unique<T>(data));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<RNGTEST>> getAllTests(std::vector<std::bitset<32>> &data){
|
||||
std::vector<std::unique_ptr<RNGTEST>> tests;
|
||||
|
||||
// add generators here
|
||||
addTest<frequency_monobit_test>(tests, data);
|
||||
addTest<frequency_block_test>(tests, data);
|
||||
addTest<runs_test>(tests, data);
|
||||
addTest<runs_ones_test>(tests, data);
|
||||
|
||||
return tests;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
|
||||
int seed = 8898;
|
||||
int seed = 235211213;
|
||||
int blocksgenerated = 1000000;
|
||||
|
||||
mt19937_generator mt2 = mt19937_generator(seed);
|
||||
lehmer_generator lg = lehmer_generator(seed);
|
||||
std::vector<std::unique_ptr<splat::PRNG>> generators = splat::getAllGenerators(1238124);
|
||||
|
||||
std::vector<std::bitset<32>> mtbits;
|
||||
std::vector<std::bitset<32>> lgbits;
|
||||
for(const std::unique_ptr<splat::PRNG> &generator : generators){
|
||||
std::cout << generator->getName() << ": \n";
|
||||
std::vector<std::bitset<32>> bits;
|
||||
for(int i=0; i<blocksgenerated; i++){
|
||||
bits.push_back(generator->generate());
|
||||
}
|
||||
|
||||
for(int i=0; i<blocksgenerated; i++){
|
||||
mtbits.push_back(mt2.generate());
|
||||
lgbits.push_back(lg.generate());
|
||||
std::vector<std::unique_ptr<splat::RNGTEST>> tests = splat::getAllTests(bits);
|
||||
|
||||
for(const std::unique_ptr<splat::RNGTEST> &test : tests){
|
||||
std::string namestr = test->getName();
|
||||
while(namestr.length() < 30){
|
||||
namestr.append(" ");
|
||||
}
|
||||
std::cout << " - " << namestr << " = " << (test->passed()?"PASS":"FAIL") << " ("<< std::fixed << std::setprecision(8) << test->value() <<")\n";
|
||||
}
|
||||
}
|
||||
|
||||
// for(auto bs : lgbits){
|
||||
// for(int i=0; i<32; i++){
|
||||
// std::cout << bs[i];
|
||||
// }
|
||||
// }
|
||||
|
||||
int freqblocksize = (blocksgenerated * 32) / 120;
|
||||
|
||||
std::cout << "Linear Congruential Generator:\n";
|
||||
std::cout << " - FreqMonobit = "<< std::fixed << std::setprecision(10) << test_frequency_monobit(lgbits) << "\n";
|
||||
std::cout << " - FreqBlock (n/120) = "<< std::fixed << std::setprecision(10) << test_frequency_block(lgbits, freqblocksize) << "\n";
|
||||
std::cout << " - Runs = "<< std::fixed << std::setprecision(10) << test_runs(lgbits) << "\n";
|
||||
|
||||
std::cout << "Mersenne Twister mt19937-32:\n";
|
||||
std::cout << " - FreqMonobit = "<< std::fixed << std::setprecision(10) << test_frequency_monobit(mtbits) << "\n";
|
||||
std::cout << " - FreqBlock (n/120) = "<< std::fixed << std::setprecision(10) << test_frequency_block(mtbits, freqblocksize) << "\n";
|
||||
std::cout << " - Runs = "<< std::fixed << std::setprecision(10) << test_runs(mtbits) << "\n";
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
BIN
rng/rng/main.o
Executable file
BIN
rng/rng/main.o
Executable file
Binary file not shown.
@ -1,20 +0,0 @@
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
x_coords = []
|
||||
y_coords = []
|
||||
|
||||
with open("data.txt", "r") as file:
|
||||
for line in file:
|
||||
x_coords.append(float(line.split(",")[0]))
|
||||
y_coords.append(float(line.split(",")[1]))
|
||||
|
||||
plt.figure(figsize=(10, 8))
|
||||
plt.scatter(x_coords, y_coords, alpha=0.6, s=1)
|
||||
plt.grid(True, alpha=0.3)
|
||||
|
||||
plt.axis('equal')
|
||||
plt.xlim(-0.05, 1.05)
|
||||
plt.ylim(-0.05, 1.05)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
@ -8,44 +8,50 @@
|
||||
#include "../rng.h"
|
||||
#include "../math/incomplete_gamma.cpp"
|
||||
|
||||
/**
|
||||
* Returns the p value from the block frequency test
|
||||
*/
|
||||
double test_frequency_block(std::vector<std::bitset<32>> data, u_long block_size){
|
||||
#include "./rngtest.h"
|
||||
|
||||
// std::cout << "BLOCK SIZE: "<< block_size<<"\n";
|
||||
namespace splat {
|
||||
class frequency_block_test : public RNGTEST {
|
||||
public:
|
||||
frequency_block_test(std::vector<std::bitset<32>> &testData) : RNGTEST(testData) {
|
||||
block_size = data.size() * 32 / 150;
|
||||
testPValue = runTest(data);
|
||||
testPassed = testPValue > 0.01;
|
||||
}
|
||||
std::string getName() override {
|
||||
return std::format("Frequency Block [{}]", block_size);
|
||||
}
|
||||
double runTest(std::vector<std::bitset<32>> &data) override {
|
||||
|
||||
long long bitcount = data.size() * 32;
|
||||
long long chunks = bitcount / block_size;
|
||||
// std::cout << "DEBUG: "<<data.size() << "\n";
|
||||
|
||||
double x2stat = 0;
|
||||
long long bitcount = data.size() * 32;
|
||||
long long chunks = bitcount / block_size;
|
||||
|
||||
for(int chunkIndex = 0; chunkIndex < chunks; chunkIndex++){
|
||||
// std::cout << "NEWCHUNK: ";
|
||||
double onecount = 0;
|
||||
for(int i=0; i<block_size; i++){
|
||||
int dataIndex = (((chunkIndex * block_size)+i) / 32);
|
||||
int bitIndex = (((chunkIndex * block_size)+i) % 32);
|
||||
onecount += data[dataIndex][bitIndex];
|
||||
// std::cout << data[dataIndex][bitIndex];
|
||||
}
|
||||
double oneproportion = onecount / (double)block_size;
|
||||
double x2stat = 0;
|
||||
|
||||
x2stat += 4*block_size*std::pow((oneproportion - 0.5),2);
|
||||
for(int chunkIndex = 0; chunkIndex < chunks; chunkIndex++){
|
||||
// std::cout << "NEWCHUNK: ";
|
||||
double onecount = 0;
|
||||
for(int i=0; i<block_size; i++){
|
||||
int dataIndex = (((chunkIndex * block_size)+i) / 32);
|
||||
int bitIndex = (((chunkIndex * block_size)+i) % 32);
|
||||
onecount += data[dataIndex][bitIndex];
|
||||
// std::cout << data[dataIndex][bitIndex];
|
||||
}
|
||||
double oneproportion = onecount / (double)block_size;
|
||||
|
||||
// std::cout << "\n";
|
||||
}
|
||||
x2stat += 4*block_size*std::pow((oneproportion - 0.5),2);
|
||||
|
||||
// std::cout << "[debug] calling igamc with "<<(chunks/2) <<','<<(x2stat/2) << "\n";
|
||||
double p = igam(chunks/2, x2stat/2);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* It is recommended that each sequence to be tested consist of a minimum of 100 bits (i.e., n ≥ 100). Note
|
||||
that n ≥ MN. The block size M should be selected such that M ≥ 20, M > .01n and N < 100.
|
||||
*/
|
||||
bool pass_frequency_monobit(std::vector<std::bitset<32>> data, int chunkSize){
|
||||
double pv = test_frequency_block(data, chunkSize);
|
||||
return pv >= 0.01;
|
||||
// std::cout << "\n";
|
||||
}
|
||||
|
||||
// std::cout << "[debug] calling igamc with "<<(chunks/2) <<','<<(x2stat/2) << "\n";
|
||||
double p = igam(chunks/2, x2stat/2);
|
||||
return p;
|
||||
}
|
||||
private:
|
||||
long long block_size;
|
||||
|
||||
};
|
||||
}
|
@ -6,30 +6,28 @@
|
||||
//
|
||||
|
||||
#include "../rng.h"
|
||||
#include "./rngtest.h"
|
||||
|
||||
|
||||
double test_frequency_monobit(std::vector<std::bitset<32>> data){
|
||||
|
||||
long long s = 0;
|
||||
|
||||
for(auto bitset : data){
|
||||
for(int i=0; i<32; i++){
|
||||
s += (2*bitset[i])-1;
|
||||
namespace splat {
|
||||
class frequency_monobit_test : public RNGTEST {
|
||||
public:
|
||||
frequency_monobit_test(std::vector<std::bitset<32>> &testData) : RNGTEST(testData) {
|
||||
testPValue = runTest(data);
|
||||
testPassed = testPValue > 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
// std::cout << " [sval: "<<s<<"] ";
|
||||
|
||||
double sobs = ((double)std::abs(s))/std::sqrt(data.size()*32);
|
||||
|
||||
|
||||
|
||||
double pvalue = std::erfc(sobs/std::sqrt(2));
|
||||
|
||||
return pvalue;
|
||||
}
|
||||
|
||||
bool pass_frequency_monobit(std::vector<std::bitset<32>> data){
|
||||
double pv = test_frequency_monobit(data);
|
||||
return pv >= 0.01;
|
||||
std::string getName() override {
|
||||
return "Frequency Monobit";
|
||||
}
|
||||
double runTest(std::vector<std::bitset<32>> &data) override {
|
||||
long long s = 0;
|
||||
for(auto bitset : data){
|
||||
for(int i=0; i<32; i++){
|
||||
s += (2*bitset[i])-1;
|
||||
}
|
||||
}
|
||||
double sobs = ((double)std::abs(s))/std::sqrt(data.size()*32);
|
||||
double pvalue = std::erfc(sobs/std::sqrt(2));
|
||||
return pvalue;
|
||||
}
|
||||
};
|
||||
}
|
25
rng/rng/randomness_tests/rngtest.h
Normal file
25
rng/rng/randomness_tests/rngtest.h
Normal file
@ -0,0 +1,25 @@
|
||||
#include "../rng.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace splat {
|
||||
class RNGTEST {
|
||||
public:
|
||||
bool passed(){
|
||||
return testPassed;
|
||||
}
|
||||
double value(){
|
||||
return testPValue;
|
||||
}
|
||||
virtual ~RNGTEST() = default;
|
||||
virtual std::string getName() {return "N/A";};
|
||||
RNGTEST(std::vector<std::bitset<32>> &testData) : data(testData){
|
||||
};
|
||||
protected:
|
||||
std::vector<std::bitset<32>> &data;
|
||||
bool testPassed;
|
||||
double testPValue;
|
||||
virtual double runTest(std::vector<std::bitset<32>> &data) {return -1.0;};
|
||||
};
|
||||
}
|
||||
|
@ -1,26 +1,38 @@
|
||||
#include "../rng.h"
|
||||
#include "./rngtest.h"
|
||||
|
||||
double test_runs(std::vector<std::bitset<32>> data){
|
||||
|
||||
long long totalSize = data.size() * 32;
|
||||
|
||||
double vnobs = 1;
|
||||
|
||||
double onesproportion = 0;
|
||||
|
||||
for(int i=0; i<totalSize-1; i++){
|
||||
|
||||
if(data[i/32][i%32]!=data[(i+1)/32][(i+1)%32]){
|
||||
vnobs++;
|
||||
namespace splat {
|
||||
class runs_test : public RNGTEST {
|
||||
public:
|
||||
runs_test(std::vector<std::bitset<32>> &testData) : RNGTEST(testData) {
|
||||
testPValue = runTest(data);
|
||||
testPassed = testPValue > 0.01;
|
||||
}
|
||||
onesproportion+=data[i/32][i%32];
|
||||
}
|
||||
std::string getName() override {
|
||||
return "Runs";
|
||||
}
|
||||
double runTest(std::vector<std::bitset<32>> &data) override {
|
||||
long long totalSize = data.size() * 32;
|
||||
|
||||
onesproportion/=totalSize;
|
||||
double vnobs = 1;
|
||||
|
||||
return std::erfc(
|
||||
std::abs(vnobs-(2*totalSize*onesproportion*(1-onesproportion)))
|
||||
/
|
||||
(2*std::sqrt(2*totalSize)*onesproportion*(1-onesproportion))
|
||||
);
|
||||
double onesproportion = 0;
|
||||
|
||||
for(int i=0; i<totalSize-1; i++){
|
||||
|
||||
if(data[i/32][i%32]!=data[(i+1)/32][(i+1)%32]){
|
||||
vnobs++;
|
||||
}
|
||||
onesproportion+=data[i/32][i%32];
|
||||
}
|
||||
|
||||
onesproportion/=totalSize;
|
||||
|
||||
return std::erfc(
|
||||
std::abs(vnobs-(2*totalSize*onesproportion*(1-onesproportion)))
|
||||
/
|
||||
(2*std::sqrt(2*totalSize)*onesproportion*(1-onesproportion))
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
78
rng/rng/randomness_tests/runs_ones.cpp
Normal file
78
rng/rng/randomness_tests/runs_ones.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "../rng.h"
|
||||
#include "./rngtest.h"
|
||||
#include "../math/incomplete_gamma.cpp"
|
||||
#define vecdebug(list) for(auto vecdebugitem : list){ std::cout << vecdebugitem <<","; }std::cout << "\n";
|
||||
|
||||
|
||||
|
||||
namespace splat {
|
||||
class runs_ones_test : public RNGTEST {
|
||||
public:
|
||||
runs_ones_test(std::vector<std::bitset<32>> &testData) : RNGTEST(testData) {
|
||||
testPValue = runTest(data);
|
||||
testPassed = testPValue > 0.01;
|
||||
}
|
||||
std::string getName() override {
|
||||
return "Runs of 1s";
|
||||
}
|
||||
double runTest(std::vector<std::bitset<32>> &data) override {
|
||||
long long totalSize = data.size() * 32;
|
||||
|
||||
if(totalSize < 750000){
|
||||
std::cout << "Error, runs of ones test requires more than 750K bits of input\n";
|
||||
return 0;
|
||||
}
|
||||
// we do it with M=10^4 here
|
||||
|
||||
std::vector<double> counts(7,0);
|
||||
|
||||
double chunks = totalSize / 10000;
|
||||
|
||||
for(int chunkIndex=0; chunkIndex<chunks; chunkIndex++){
|
||||
|
||||
int longestRun = 0;
|
||||
|
||||
int ones = 0;
|
||||
|
||||
for(int i=0; i<10000; i++){
|
||||
long long index = chunkIndex*10000 + i;
|
||||
int dataIndex = (index / 32);
|
||||
int bitIndex = (index % 32);
|
||||
|
||||
if(data[dataIndex][bitIndex]){
|
||||
ones++;
|
||||
}else{
|
||||
if(ones>longestRun) longestRun = ones;
|
||||
ones = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(longestRun <=10){
|
||||
counts[0]++;
|
||||
}else if(longestRun>=16){
|
||||
counts[6]++;
|
||||
}else{
|
||||
counts[longestRun-10]++;
|
||||
}
|
||||
}
|
||||
|
||||
double x2 = 0;
|
||||
|
||||
std::vector<double> probabilities = {
|
||||
0.0882,
|
||||
0.2092,
|
||||
0.2483,
|
||||
0.1933,
|
||||
0.1208,
|
||||
0.0675,
|
||||
0.0727
|
||||
};
|
||||
|
||||
for(int i=0; i<7; i++){
|
||||
x2 += std::pow((counts[i] - (chunks * probabilities[i])),2.0) /(chunks * probabilities[i]);
|
||||
|
||||
}
|
||||
return igamc(3, x2/2.0);
|
||||
}
|
||||
};
|
||||
}
|
2
rng/rng/readme.md
Normal file
2
rng/rng/readme.md
Normal file
@ -0,0 +1,2 @@
|
||||
Splatter
|
||||
c++ rng library with generators and tests
|
@ -14,3 +14,4 @@
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <format>
|
@ -1,3 +1,2 @@
|
||||
g++ -std=c++11 main.cpp -o main.o
|
||||
g++ -std=c++20 main.cpp -o main.o
|
||||
./main.o
|
||||
rm main.o
|
Loading…
x
Reference in New Issue
Block a user