Mam 3 generatory PRNG, których czasy chcę zmierzyć. Xoroshiro128+:
#include <stdint.h>
#include <iostream>
#include <chrono>
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
static uint64_t s[2] = {9,5};
uint64_t next(void) {
const uint64_t s0 = s[0];
uint64_t s1 = s[1];
const uint64_t result = s0 + s1;
s1 ^= s0;
s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
s[1] = rotl(s1, 37); // c
return result;
}
int main()
{
double a=0;
uint64_t result;
for(int i=0; i<100; i++)
{
auto begin = std::chrono::high_resolution_clock::now();
for(int i=0; i<320000000; i++)
//while (true)
{
result = next();
//std::cout << result << "\n";
//char *c = reinterpret_cast<char*>(&result);
//std::cout.write(reinterpret_cast<char*>(&result), sizeof result);
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.3f seconds.\n", elapsed.count() * 1e-9);
a = a + (elapsed.count() * 1e-9);
}
__asm__ volatile("" : "+g" (result) : :);
std::cout << a/100;
}
Kod wzięty stąd: https://prng.di.unimi.it/xoroshiro128plus.c. Generator Lehmera 64-bitowy truncated (mój własny kod):
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <chrono>
uint64_t LCG(uint64_t LCG_state)
{
LCG_state = (LCG_state * 2862933555777941757 + 1422359891750319841);
return LCG_state;
}
int main()
{
auto begin = std::chrono::high_resolution_clock::now();
double a = 0;
uint64_t LCG_state = 333;
uint32_t result;
for(int i=0; i<100; i++)
{
auto begin = std::chrono::high_resolution_clock::now();
for(int i=0; i<640000000; i++)
{
LCG_state = LCG(LCG_state);
result = LCG_state >> 32;
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.3f seconds.\n", elapsed.count() * 1e-9);
a = a + (elapsed.count() * 1e-9);
}
__asm__ volatile("" : "+g" (result) : :);
std::cout << a/100;
}
Oraz generator PCG:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdint.h>
#include <chrono>
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng)
{
uint64_t oldstate = rng->state;
// Advance internal state
rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
// Calculate output function (XSH RR), uses old state for max ILP
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
int main()
{
double a = 0;
uint32_t result;
pcg32_random_t rnd_ctx = {123, 111};
for(int i=0; i<100; i++)
{
auto begin = std::chrono::high_resolution_clock::now();
for(int i=0; i<640000000; i++)
{
result = pcg32_random_r(&rnd_ctx);
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
printf("Time measured: %.3f seconds.\n", elapsed.count() * 1e-9);
a = a + (elapsed.count() * 1e-9);
}
__asm__ volatile("" : "+g" (result) : :);
std::cout << a/100;
}
Kod stąd: https://www.pcg-random.org/download.html.
Robię pomiary czasu i otrzymałem następujące wyniki dla tych generatorów:
- LCG ok. 1 sekunda,
- PCG ok. 1 sekunda,
- xoroshiro128+ około 1,5 sekundy.
Zauważcie, że xoroshiro128+ ma mniej powtórzeń, bo zwraca liczby 64-bitowe, a ja chcę zmierzyć sekundy na bajt. Problem polega na tym, że xoroshiro128+ powinien być znacznie szybszy niż pozostałe dwa generatory. Mierzę kod w trybie release. Ale wciąż coś zdaje się istotnie zaburza mi wyniki.
Co Wam wychodzi i, czy jest jeszcze coś, co powinienem zrobić, żeby te wyniki były bardziej obiektywne?