ppsspp/Common/Data/Random/Rng.h
2021-02-18 22:25:24 -08:00

73 lines
1.5 KiB
C++

#pragma once
#include <cstdint>
#include "Common/Swap.h"
// George Marsaglia-style random number generator.
class GMRng {
public:
GMRng() {
m_w = 0x23E866ED;
m_z = 0x80FD5AF2;
}
void Init(int seed) {
m_w = seed ^ (seed << 16);
if (!m_w) m_w = 1337;
m_z = ~seed;
if (!m_z) m_z = 31337;
}
uint32_t R32() {
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
float F() {
return (float)R32() / (float)(0xFFFFFFFF);
}
// public for easy save/load. Yes a bit ugly but better than moving DoState into native.
uint32_t m_w;
uint32_t m_z;
};
// Data must consist only of the index and the twister array. This matches the PSP
// MT context exactly.
class MersenneTwister {
public:
MersenneTwister(uint32_t seed) : index_(0) {
mt_[0] = seed;
for (uint32_t i = 1; i < MT_SIZE; i++)
mt_[i] = (1812433253UL * (mt_[i - 1] ^ (mt_[i - 1] >> 30)) + i);
}
uint32_t R32() {
if (index_ == 0)
gen();
uint32_t y = mt_[index_];
y ^= y >> 11;
y ^= (y << 7) & 2636928640UL;
y ^= (y << 15) & 4022730752UL;
y ^= y >> 18;
index_ = (index_ + 1) % MT_SIZE;
return y;
}
private:
enum {
MT_SIZE = 624,
};
u32_le index_;
u32_le mt_[MT_SIZE];
void gen() {
for(uint32_t i = 0; i < MT_SIZE; i++){
uint32_t y = (mt_[i] & 0x80000000) + (mt_[(i + 1) % MT_SIZE] & 0x80000000);
mt_[i] = mt_[(i + 397) % MT_SIZE] ^ (y >> 1);
if (y % 2) mt_[i] ^= 2567483615UL;
}
return;
}
};