Improve random

This commit is contained in:
NSDeathman 2026-03-11 20:04:11 +03:00
parent fb87883b54
commit 3d96a0ebdb
6 changed files with 446 additions and 230 deletions

View file

@ -9,7 +9,7 @@
class PerlinNoise_SPU//: public Synth
{
private:
static const int MAX_NOISE_LEVELS = 16;
static const int MAX_NOISE_LEVELS = 256;
ImprovedNoise_SPU noiseLevels[MAX_NOISE_LEVELS];
int levels;

View file

@ -1,216 +1,219 @@
#include "stdafx.h"
#include "ImprovedNoise.h"
#include "Random.h" // íàø óëó÷øåííûé Random
#include <cmath> // äëÿ floor, åñëè íóæíî, íî èñïîëüçóåì static_cast
ImprovedNoise::ImprovedNoise()
{
Random random;
init(&random);
Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
init(&random);
}
ImprovedNoise::ImprovedNoise(Random *random)
ImprovedNoise::ImprovedNoise(Random* random)
{
init(random);
init(random);
}
void ImprovedNoise::init(Random *random)
void ImprovedNoise::init(Random* random)
{
p = new int[512];
// Ñëó÷àéíûå ñìåùåíèÿ äëÿ êàæäîé êîîðäèíàòû (óáèðàþò ñèììåòðèþ)
xo = random->nextDouble() * 256.0;
yo = random->nextDouble() * 256.0;
zo = random->nextDouble() * 256.0;
xo = random->nextDouble() * 256;
yo = random->nextDouble() * 256;
zo = random->nextDouble() * 256;
for (int i = 0; i < 256; i++)
{
// Çàïîëíÿåì permutation table ÷èñëàìè 0..255 â ñëó÷àéíîì ïîðÿäêå
for (int i = 0; i < 256; ++i)
p[i] = i;
}
for (int i = 0; i < 256; i++)
{
int j = random->nextInt(256 - i) + i;
for (int i = 0; i < 256; ++i)
{
int j = random->nextInt(256 - i) + i; // ñëó÷àéíàÿ ïåðåñòàíîâêà
int tmp = p[i];
p[i] = p[j];
p[j] = tmp;
p[i + 256] = p[i];
p[i + 256] = p[i]; // äóáëèðóåì äëÿ èçáåæàíèÿ ïðîâåðîê ãðàíèö
}
}
ImprovedNoise::~ImprovedNoise()
// ----------------------------------------------------------------------
// Îñíîâíîé ìåòîä âû÷èñëåíèÿ 3D øóìà Ïåðëèíà
double ImprovedNoise::noise(double x, double y, double z) const
{
delete [] p;
}
// Äîáàâëÿåì óíèêàëüíîå ñìåùåíèå äëÿ ýòîãî ýêçåìïëÿðà
x += xo;
y += yo;
z += zo;
double ImprovedNoise::noise(double _x, double _y, double _z)
{
double x = _x + xo;
double y = _y + yo;
double z = _z + zo;
// Öåëàÿ ÷àñòü êîîðäèíàò (îïðåäåëÿåì êóá, ñîäåðæàùèé òî÷êó)
int X = static_cast<int>(std::floor(x)) & 255;
int Y = static_cast<int>(std::floor(y)) & 255;
int Z = static_cast<int>(std::floor(z)) & 255;
int xf = static_cast<int>(x);
int yf = static_cast<int>(y);
int zf = static_cast<int>(z);
// Îòíîñèòåëüíûå êîîðäèíàòû âíóòðè êóáà [0,1)
x -= std::floor(x);
y -= std::floor(y);
z -= std::floor(z);
if (x < xf) xf--;
if (y < yf) yf--;
if (z < zf) zf--;
// Ïëàâíàÿ êðèâàÿ (fade function): 6t^5 - 15t^4 + 10t^3
double u = x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
double v = y * y * y * (y * (y * 6.0 - 15.0) + 10.0);
double w = z * z * z * (z * (z * 6.0 - 15.0) + 10.0);
int X = xf & 255, // FIND UNIT CUBE THAT
Y = yf & 255, // CONTAINS POINT.
Z = zf & 255;
// Õåøè èíäåêñîâ âîñüìè óãëîâ êóáà
int A = p[X] + Y;
int AA = p[A] + Z;
int AB = p[A + 1] + Z;
int B = p[X + 1] + Y;
int BA = p[B] + Z;
int BB = p[B + 1] + Z;
x -= xf; // FIND RELATIVE X,Y,Z
y -= yf; // OF POINT IN CUBE.
z -= zf;
double u = x * x * x * (x * (x * 6 - 15) + 10), // COMPUTE FADE CURVES
v = y * y * y * (y * (y * 6 - 15) + 10), // FOR EACH OF X,Y,Z.
w = z * z * z * (z * (z * 6 - 15) + 10);
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF
B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS,
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD
grad(p[BA], x - 1, y, z)), // BLENDED
lerp(u, grad(p[AB], x, y - 1, z), // RESULTS
grad(p[BB], x - 1, y - 1, z))),// FROM 8
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS
grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
// Èíòåðïîëÿöèÿ
double y1 = lerp(u,
grad(p[AA], x, y, z),
grad(p[BA], x - 1, y, z));
double y2 = lerp(u,
grad(p[AB], x, y - 1, z),
grad(p[BB], x - 1, y - 1, z));
double y3 = lerp(u,
grad(p[AA + 1], x, y, z - 1),
grad(p[BA + 1], x - 1, y, z - 1));
double y4 = lerp(u,
grad(p[AB + 1], x, y - 1, z - 1),
grad(p[BB + 1], x - 1, y - 1, z - 1));
double z1 = lerp(v, y1, y2);
double z2 = lerp(v, y3, y4);
return lerp(w, z1, z2);
}
double ImprovedNoise::lerp(double t, double a, double b)
{
return a + t * (b - a);
}
double ImprovedNoise::grad2(int hash, double x, double z)
{
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
double u = (1-((h&8)>>3))*x, // INTO 12 GRADIENT DIRECTIONS.
v = h < 4 ? 0 : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
return a + t * (b - a);
}
// 3D ãðàäèåíò (èñïîëüçóåòñÿ â noise)
double ImprovedNoise::grad(int hash, double x, double y, double z)
{
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
v = h < 4 ? y : h == 12 || h == 14 ? x : z;
int h = hash & 15; // ìëàäøèå 4 áèòà
double u = h < 8 ? x : y;
double v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
// 2D ãðàäèåíò (èñïîëüçóåòñÿ â add() äëÿ ñëó÷àÿ ySize==1)
double ImprovedNoise::grad2(int hash, double x, double z)
{
int h = hash & 15;
double u = (h & 8) ? x : z; // àëüòåðíàòèâíîå ðàñïðåäåëåíèå äëÿ 2D
double v = (h < 4) ? 0 : (h == 12 || h == 14 ? x : z);
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
// Synth èíòåðôåéñ
double ImprovedNoise::getValue(double x, double y)
{
return noise(x, y, 0);
return noise(x, y, 0.0);
}
double ImprovedNoise::getValue(double x, double y, double z)
{
return noise(x, y, z);
return noise(x, y, z);
}
void ImprovedNoise::add(doubleArray buffer, double _x, double _y, double _z, int xSize, int ySize, int zSize, double xs, double ys, double zs, double pow)
// ----------------------------------------------------------------------
// Ìåòîä add áûñòðîå çàïîëíåíèå áóôåðà çíà÷åíèÿìè øóìà äëÿ ïðÿìîóãîëüíîé îáëàñòè
// (îïòèìèçèðîâàí, ÷òîáû èçáåæàòü ïîâòîðíûõ âû÷èñëåíèé ãðàäèåíòîâ)
void ImprovedNoise::add(doubleArray buffer, double _x, double _y, double _z,
int xSize, int ySize, int zSize,
double xs, double ys, double zs, double pow) const
{
if (ySize==1)
{
int A = 0, AA = 0, B = 0, BA = 0;
double vv0 = 0, vv2 = 0;
int pp = 0;
double scale = 1.0 / pow;
for (int xx = 0; xx < xSize; xx++)
{
double x = _x + (xx) * xs + xo;
int xf = static_cast<int>(x);
if (x < xf) xf--;
int X = xf & 255;
x -= xf;
double u = x * x * x * (x * (x * 6 - 15) + 10);
double invPow = 1.0 / pow;
int idx = 0; // èíäåêñ â áóôåðå
for (int zz = 0; zz < zSize; zz++)
{
double z = _z + (zz) * zs + zo;
int zf = static_cast<int>(z);
if (z < zf) zf--;
int Z = zf & 255;
z -= zf;
double w = z * z * z * (z * (z * 6 - 15) + 10);
A = p[X] + 0;
AA = p[A] + Z;
B = p[X + 1] + 0;
BA = p[B] + Z;
vv0 = lerp(u, grad2(p[AA], x, z), grad(p[BA], x - 1, 0, z));
vv2 = lerp(u, grad(p[AA + 1], x, 0, z - 1), grad(p[BA + 1], x - 1, 0, z - 1));
if (ySize == 1)
{
// Îïòèìèçàöèÿ äëÿ 2D ñðåçà (y ôèêñèðîâàí)
for (int xx = 0; xx < xSize; ++xx)
{
double x = _x + xx * xs + xo;
int X = static_cast<int>(std::floor(x)) & 255;
double dx = x - std::floor(x);
double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
double val = lerp(w, vv0, vv2);
for (int zz = 0; zz < zSize; ++zz)
{
double z = _z + zz * zs + zo;
int Z = static_cast<int>(std::floor(z)) & 255;
double dz = z - std::floor(z);
double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
buffer[pp++] += val * scale;
int A = p[X];
int AA = p[A] + Z;
int B = p[X + 1];
int BA = p[B] + Z;
double v0 = lerp(u,
grad2(p[AA], dx, dz),
grad2(p[BA], dx - 1.0, dz));
double v2 = lerp(u,
grad2(p[AA + 1], dx, dz - 1.0),
grad2(p[BA + 1], dx - 1.0, dz - 1.0));
buffer[idx++] += lerp(w, v0, v2) * invPow;
}
}
return;
}
int pp = 0;
double scale = 1 / pow;
int yOld = -1;
int A = 0, AA = 0, AB = 0, B = 0, BA = 0, BB = 0;
double vv0 = 0, vv1 = 0, vv2 = 0, vv3 = 0;
else
{
// Ïîëíàÿ 3D âåðñèÿ ñ êýøèðîâàíèåì ïî Y
int yPrev = -1;
int A, AA, AB, B, BA, BB;
double vv0, vv1, vv2, vv3;
for (int xx = 0; xx < xSize; xx++)
{
double x = _x + (xx) * xs + xo;
int xf = static_cast<int>(x);
if (x < xf) xf--;
int X = xf & 255;
x -= xf;
double u = x * x * x * (x * (x * 6 - 15) + 10);
for (int xx = 0; xx < xSize; ++xx)
{
double x = _x + xx * xs + xo;
int X = static_cast<int>(std::floor(x)) & 255;
double dx = x - std::floor(x);
double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
for (int zz = 0; zz < zSize; ++zz)
{
double z = _z + zz * zs + zo;
int Z = static_cast<int>(std::floor(z)) & 255;
double dz = z - std::floor(z);
double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
for (int zz = 0; zz < zSize; zz++)
{
double z = _z + (zz) * zs + zo;
int zf = static_cast<int>(z);
if (z < zf) zf--;
int Z = zf & 255;
z -= zf;
double w = z * z * z * (z * (z * 6 - 15) + 10);
for (int yy = 0; yy < ySize; ++yy)
{
double y = _y + yy * ys + yo;
int Y = static_cast<int>(std::floor(y)) & 255;
double dy = y - std::floor(y);
double v = dy * dy * dy * (dy * (dy * 6.0 - 15.0) + 10.0);
// Êýøèðóåì çíà÷åíèÿ, çàâèñÿùèå òîëüêî îò Y
if (yy == 0 || Y != yPrev)
{
yPrev = Y;
A = p[X] + Y;
AA = p[A] + Z;
AB = p[A + 1] + Z;
B = p[X + 1] + Y;
BA = p[B] + Z;
BB = p[B + 1] + Z;
for (int yy = 0; yy < ySize; yy++)
{
double y = _y + (yy) * ys + yo;
int yf = static_cast<int>(y);
if (y < yf) yf--;
int Y = yf & 255;
y -= yf;
double v = y * y * y * (y * (y * 6 - 15) + 10);
vv0 = lerp(u, grad(p[AA], dx, dy, dz), grad(p[BA], dx - 1.0, dy, dz));
vv1 = lerp(u, grad(p[AB], dx, dy - 1.0, dz), grad(p[BB], dx - 1.0, dy - 1.0, dz));
vv2 = lerp(u, grad(p[AA + 1], dx, dy, dz - 1.0), grad(p[BA + 1], dx - 1.0, dy, dz - 1.0));
vv3 = lerp(u, grad(p[AB + 1], dx, dy - 1.0, dz - 1.0), grad(p[BB + 1], dx - 1.0, dy - 1.0, dz - 1.0));
}
if (yy == 0 || Y != yOld)
{
yOld = Y;
A = p[X] + Y;
AA = p[A] + Z;
AB = p[A + 1] + Z;
B = p[X + 1] + Y;
BA = p[B] + Z;
BB = p[B + 1] + Z;
vv0 = lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z));
vv1 = lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z));
vv2 = lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1));
vv3 = lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1));
double v0 = lerp(v, vv0, vv1);
double v1 = lerp(v, vv2, vv3);
buffer[idx++] += lerp(w, v0, v1) * invPow;
}
double v0 = lerp(v, vv0, vv1);
double v1 = lerp(v, vv2, vv3);
double val = lerp(w, v0, v1);
buffer[pp++] += val * scale;
}
}
}
}
}

View file

@ -1,29 +1,28 @@
#pragma once
#pragma once
#include "Synth.h"
class ImprovedNoise : public Synth
{
friend class PerlinNoise_SPU;
friend class PerlinNoise_SPU;
private:
int *p;
int p[512]; // permutation table (size 512 for easy indexing)
double xo, yo, zo; // random offsets for each instance
public:
double scale;
double xo, yo, zo;
ImprovedNoise();
ImprovedNoise(Random *random);
void init(Random *random);
explicit ImprovedNoise(Random* random);
void init(Random* random);
~ImprovedNoise();
double noise(double x, double y, double z) const;
static double lerp(double t, double a, double b);
static double grad(int hash, double x, double y, double z);
static double grad2(int hash, double x, double z); // 2D gradient (used in add() for ySize==1)
double noise(double _x, double _y, double _z);
// Synth interface
double getValue(double x, double y) override; // 2D noise (z = 0)
double getValue(double x, double y, double z); // 3D noise
double lerp(double t, double a, double b);
double grad2(int hash, double x, double z);
double grad(int hash, double x, double y, double z);
virtual double getValue(double x, double y);
double getValue(double x, double y, double z);
void add(doubleArray buffer, double _x, double _y, double _z, int xSize, int ySize, int zSize, double xs, double ys, double zs, double pow);
void add(doubleArray buffer, double _x, double _y, double _z,
int xSize, int ySize, int zSize,
double xs, double ys, double zs, double pow) const;
};

View file

@ -1,98 +1,98 @@
#include "stdafx.h"
#include "PerlinNoise.h"
#include "Random.h"
#include "Mth.h"
PerlinNoise::PerlinNoise(int levels)
{
Random random;
init(&random, levels);
Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
init(&random, levels);
}
PerlinNoise::PerlinNoise(Random *random, int levels)
PerlinNoise::PerlinNoise(Random* random, int levels)
{
init(random, levels);
init(random, levels);
}
void PerlinNoise::init(Random *random, int levels)
void PerlinNoise::init(Random* random, int levels)
{
MemSect(2);
MemSect(2);
this->levels = levels;
noiseLevels = new ImprovedNoise *[levels];
for (int i = 0; i < levels; i++)
{
noiseLevels = new ImprovedNoise * [levels];
for (int i = 0; i < levels; ++i)
{
noiseLevels[i] = new ImprovedNoise(random);
}
MemSect(0);
MemSect(0);
}
PerlinNoise::~PerlinNoise()
{
for( int i = 0; i < levels; i++ )
{
delete noiseLevels[i];
}
delete [] noiseLevels;
for (int i = 0; i < levels; ++i)
delete noiseLevels[i];
delete[] noiseLevels;
}
double PerlinNoise::getValue(double x, double y)
{
double value = 0;
double pow = 1;
for (int i = 0; i < levels; i++)
{
value += noiseLevels[i]->getValue(x * pow, y * pow) / pow;
pow /= 2;
double value = 0.0;
double amp = 1.0; // àìïëèòóäà (çäåñü 1/pow â îðèãèíàëå)
for (int i = 0; i < levels; ++i)
{
value += noiseLevels[i]->getValue(x * amp, y * amp) / amp;
amp *= 0.5; // óìåíüøàåì ÷àñòîòó (pow /= 2)
}
return value;
}
double PerlinNoise::getValue(double x, double y, double z)
{
double value = 0;
double pow = 1;
for (int i = 0; i < levels; i++)
{
value += noiseLevels[i]->getValue(x * pow, y * pow, z * pow) / pow;
pow /= 2;
double value = 0.0;
double amp = 1.0;
for (int i = 0; i < levels; ++i)
{
value += noiseLevels[i]->getValue(x * amp, y * amp, z * amp) / amp;
amp *= 0.5;
}
return value;
}
doubleArray PerlinNoise::getRegion(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale)
doubleArray PerlinNoise::getRegion(doubleArray buffer,
int x, int y, int z,
int xSize, int ySize, int zSize,
double xScale, double yScale, double zScale)
{
if (buffer.data == nullptr) buffer = doubleArray(xSize * ySize * zSize);
else for (unsigned int i = 0; i < buffer.length; i++)
buffer[i] = 0;
// Èíèöèàëèçàöèÿ áóôåðà íóëÿìè, åñëè íåîáõîäèìî
if (buffer.data == nullptr)
buffer = doubleArray(xSize * ySize * zSize);
else
for (unsigned int i = 0; i < buffer.length; ++i)
buffer[i] = 0.0;
double pow = 1;
for (int i = 0; i < levels; i++)
{
// value += noiseLevels[i].getValue(x * pow, y * pow, z * pow) / pow;
double xx = x * pow * xScale;
double yy = y * pow * yScale;
double zz = z * pow * zScale;
int64_t xb = Mth::lfloor(xx);
int64_t zb = Mth::lfloor(zz);
xx -= xb;
zz -= zb;
xb %= 16777216;
zb %= 16777216;
xx += xb;
zz += zb;
noiseLevels[i]->add(buffer, xx, yy, zz, xSize, ySize, zSize, xScale * pow, yScale * pow, zScale * pow, pow);
pow /= 2;
double freq = 1.0; // ÷àñòîòà (pow)
for (int i = 0; i < levels; ++i)
{
// Âûçîâ add äëÿ òåêóùåãî óðîâíÿ ñ ïðàâèëüíûì ìàñøòàáèðîâàíèåì
noiseLevels[i]->add(buffer,
x * freq * xScale,
y * freq * yScale,
z * freq * zScale,
xSize, ySize, zSize,
xScale * freq,
yScale * freq,
zScale * freq,
freq);
freq *= 0.5;
}
return buffer;
}
doubleArray PerlinNoise::getRegion(doubleArray sr, int x, int z, int xSize, int zSize, double xScale, double zScale, double pow)
// Ïåðåãðóçêà äëÿ 2D ðåãèîíà (y ôèêñèðîâàí)
doubleArray PerlinNoise::getRegion(doubleArray sr, int x, int z,
int xSize, int zSize,
double xScale, double zScale, double pow)
{
return getRegion(sr, x, 10, z, xSize, 1, zSize, xScale, 1, zScale);
}
// Èñïîëüçóåì y = 10 (êàê â îðèãèíàëå), ySize = 1
return getRegion(sr, x, 10, z, xSize, 1, zSize, xScale, 1.0, zScale);
}

View file

@ -1,7 +1,193 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Random.h"
#include "System.h"
#ifndef USE_LEGACY_RANDOM
// Windows API for high-resolution counters and system info
#include <windows.h>
// C++11 random library and chrono for high-quality seeding
#include <random>
#include <chrono>
#include <thread>
// Use a 64-bit Mersenne Twister engine
static std::mt19937_64& getEngine() {
// Make the engine thread-local to avoid data races in multi-threaded code
thread_local std::mt19937_64 engine(std::random_device{}());
return engine;
}
// ----------------------------------------------------------------------
// Seed generation: combine multiple entropy sources
static int64_t generateEntropySeed()
{
uint64_t entropy = 0;
// 1. High-resolution performance counter (similar to original)
LARGE_INTEGER perfCount;
QueryPerformanceCounter(&perfCount);
entropy ^= perfCount.QuadPart;
// 2. System tick count (milliseconds since boot)
entropy ^= GetTickCount64();
// 3. Process and thread IDs
entropy ^= static_cast<uint64_t>(GetCurrentProcessId()) << 32;
entropy ^= static_cast<uint64_t>(GetCurrentThreadId()) << 16;
// 4. High-resolution clock with nanoseconds (C++11)
auto now = std::chrono::high_resolution_clock::now();
auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(now)
.time_since_epoch().count();
entropy ^= static_cast<uint64_t>(ns);
// 5. Hardware randomness if available (via random_device)
// Note: on some compilers random_device may be deterministic,
// but it's a good additional source.
try {
std::random_device rd;
entropy ^= static_cast<uint64_t>(rd()) |
(static_cast<uint64_t>(rd()) << 32);
}
catch (...) {
// random_device not available just ignore
}
// 6. Address of a stack variable (ASLR provides some randomness)
volatile void* stackAddr = &entropy;
entropy ^= reinterpret_cast<uintptr_t>(stackAddr);
// Mix the bits well to avoid correlation
// (using a simple but effective hash)
entropy ^= entropy >> 33;
entropy *= 0xff51afd7ed558ccdULL;
entropy ^= entropy >> 33;
entropy *= 0xc4ceb9fe1a85ec53ULL;
entropy ^= entropy >> 33;
return static_cast<int64_t>(entropy);
}
// ----------------------------------------------------------------------
// Random class implementation
Random::Random()
{
// Use the highentropy seed generator
setSeed(generateEntropySeed());
}
Random::Random(int64_t seed)
{
setSeed(seed);
}
void Random::setSeed(int64_t s)
{
// Store seed for possible inspection
seed = s;
// Seed the Mersenne Twister engine
getEngine().seed(static_cast<uint64_t>(s));
// Reset Gaussian cache
haveNextNextGaussian = false;
nextNextGaussian = 0.0;
}
// ----------------------------------------------------------------------
// Core bit generator replaces the old LCG
int Random::next(int bits)
{
// mt19937_64 produces 64 random bits each call
uint64_t raw = getEngine()();
// Return the required number of most significant bits
// (shifting right keeps the higher bits which are usually "more random")
return static_cast<int>(raw >> (64 - bits));
}
// ----------------------------------------------------------------------
// All other methods stay exactly as in the original code,
// because they all rely on next(bits).
void Random::nextBytes(byte* bytes, unsigned int count)
{
for (unsigned int i = 0; i < count; ++i)
{
bytes[i] = static_cast<byte>(next(8));
}
}
double Random::nextDouble()
{
return ((static_cast<int64_t>(next(26)) << 27) + next(27))
/ static_cast<double>(1LL << 53);
}
double Random::nextGaussian()
{
if (haveNextNextGaussian)
{
haveNextNextGaussian = false;
return nextNextGaussian;
}
else
{
double v1, v2, s;
do
{
v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = sqrt(-2 * log(s) / s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
int Random::nextInt()
{
return next(32);
}
int Random::nextInt(int n)
{
// Parameter check (you may replace assert with a thrown exception)
// assert(n > 0);
if (n <= 0) return 0; // or throw std::invalid_argument("n must be positive");
// Special case for powers of two (fast path)
if ((n & -n) == n)
return static_cast<int>((static_cast<int64_t>(next(31)) * n) >> 31);
int bits, val;
do
{
bits = next(31);
val = bits % n;
} while (bits - val + (n - 1) < 0);
return val;
}
float Random::nextFloat()
{
return next(24) / static_cast<float>(1 << 24);
}
int64_t Random::nextLong()
{
return (static_cast<int64_t>(next(32)) << 32) + next(32);
}
bool Random::nextBoolean()
{
return next(1) != 0;
}
#else
Random::Random()
{
// 4J - jave now uses the system nanosecond counter added to a "seedUniquifier" to get an initial seed. Our nanosecond timer is actually only millisecond accuate, so
@ -103,4 +289,5 @@ int64_t Random::nextLong()
bool Random::nextBoolean()
{
return next(1) != 0;
}
}
#endif

View file

@ -1,5 +1,31 @@
#pragma once
#ifndef USE_LEGACY_RANDOM
class Random
{
private:
int64_t seed; // last seed used (for reference)
bool haveNextNextGaussian; // state for nextGaussian()
double nextNextGaussian; // cached Gaussian value
protected:
int next(int bits); // generates up to 32 random bits
public:
Random(); // uses a high-entropy seed
explicit Random(int64_t seed); // seed with a specific value
void setSeed(int64_t s); // re-seed the generator
void nextBytes(byte* bytes, unsigned int count);
double nextDouble();
double nextGaussian();
int nextInt();
int nextInt(int n); // in [0, n)
float nextFloat();
int64_t nextLong();
bool nextBoolean();
};
#else
class Random
{
private:
@ -20,4 +46,5 @@ public:
float nextFloat();
int64_t nextLong();
bool nextBoolean();
};
};
#endif