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 class PerlinNoise_SPU//: public Synth
{ {
private: private:
static const int MAX_NOISE_LEVELS = 16; static const int MAX_NOISE_LEVELS = 256;
ImprovedNoise_SPU noiseLevels[MAX_NOISE_LEVELS]; ImprovedNoise_SPU noiseLevels[MAX_NOISE_LEVELS];
int levels; int levels;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "ImprovedNoise.h" #include "ImprovedNoise.h"
#include "Random.h" // íàø óëó÷øåííûé Random
#include <cmath> // äëÿ floor, åñëè íóæíî, íî èñïîëüçóåì static_cast
ImprovedNoise::ImprovedNoise() ImprovedNoise::ImprovedNoise()
{ {
Random random; Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
init(&random); init(&random);
} }
@ -14,69 +16,75 @@ ImprovedNoise::ImprovedNoise(Random *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; // Çàïîëíÿåì permutation table ÷èñëàìè 0..255 â ñëó÷àéíîì ïîðÿäêå
yo = random->nextDouble() * 256; for (int i = 0; i < 256; ++i)
zo = random->nextDouble() * 256;
for (int i = 0; i < 256; i++)
{
p[i] = i; p[i] = i;
}
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; ++i)
{ {
int j = random->nextInt(256 - i) + i; int j = random->nextInt(256 - i) + i; // ñëó÷àéíàÿ ïåðåñòàíîâêà
int tmp = p[i]; int tmp = p[i];
p[i] = p[j]; p[i] = p[j];
p[j] = tmp; 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) // Öåëàÿ ÷àñòü êîîðäèíàò (îïðåäåëÿåì êóá, ñîäåðæàùèé òî÷êó)
{ int X = static_cast<int>(std::floor(x)) & 255;
double x = _x + xo; int Y = static_cast<int>(std::floor(y)) & 255;
double y = _y + yo; int Z = static_cast<int>(std::floor(z)) & 255;
double z = _z + zo;
int xf = static_cast<int>(x); // Îòíîñèòåëüíûå êîîðäèíàòû âíóòðè êóáà [0,1)
int yf = static_cast<int>(y); x -= std::floor(x);
int zf = static_cast<int>(z); y -= std::floor(y);
z -= std::floor(z);
if (x < xf) xf--; // Ïëàâíàÿ êðèâàÿ (fade function): 6t^5 - 15t^4 + 10t^3
if (y < yf) yf--; double u = x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
if (z < zf) zf--; 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. int A = p[X] + Y;
Z = zf & 255; 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. double y1 = lerp(u,
z -= zf; grad(p[AA], x, y, z),
grad(p[BA], x - 1, y, z));
double u = x * x * x * (x * (x * 6 - 15) + 10), // COMPUTE FADE CURVES double y2 = lerp(u,
v = y * y * y * (y * (y * 6 - 15) + 10), // FOR EACH OF X,Y,Z. grad(p[AB], x, y - 1, z),
w = z * z * z * (z * (z * 6 - 15) + 10); grad(p[BB], x - 1, y - 1, z));
double y3 = lerp(u,
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF grad(p[AA + 1], x, y, z - 1),
B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS, grad(p[BA + 1], x - 1, y, z - 1));
double y4 = lerp(u,
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD grad(p[AB + 1], x, y - 1, z - 1),
grad(p[BA], x - 1, y, z)), // BLENDED grad(p[BB + 1], x - 1, y - 1, z - 1));
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 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) double ImprovedNoise::lerp(double t, double a, double b)
@ -84,29 +92,28 @@ double ImprovedNoise::lerp(double t, double a, double b)
return a + t * (b - a); return a + t * (b - a);
} }
double ImprovedNoise::grad2(int hash, double x, double z) // 3D ãðàäèåíò (èñïîëüçóåòñÿ â noise)
{
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);
}
double ImprovedNoise::grad(int hash, double x, double y, double z) double ImprovedNoise::grad(int hash, double x, double y, double z)
{ {
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE int h = hash & 15; // ìëàäøèå 4 áèòà
double u = h < 8 ? x : y;
double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. double v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 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) 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) double ImprovedNoise::getValue(double x, double y, double z)
@ -114,102 +121,98 @@ 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
{ {
double invPow = 1.0 / pow;
int idx = 0; // èíäåêñ â áóôåðå
if (ySize == 1) if (ySize == 1)
{ {
int A = 0, AA = 0, B = 0, BA = 0; // Îïòèìèçàöèÿ äëÿ 2D ñðåçà (y ôèêñèðîâàí)
double vv0 = 0, vv2 = 0; for (int xx = 0; xx < xSize; ++xx)
int pp = 0;
double scale = 1.0 / pow;
for (int xx = 0; xx < xSize; xx++)
{ {
double x = _x + (xx) * xs + xo; double x = _x + xx * xs + xo;
int xf = static_cast<int>(x); int X = static_cast<int>(std::floor(x)) & 255;
if (x < xf) xf--; double dx = x - std::floor(x);
int X = xf & 255; double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
x -= xf;
double u = x * x * x * (x * (x * 6 - 15) + 10);
for (int zz = 0; zz < zSize; zz++) for (int zz = 0; zz < zSize; ++zz)
{ {
double z = _z + (zz) * zs + zo; double z = _z + zz * zs + zo;
int zf = static_cast<int>(z); int Z = static_cast<int>(std::floor(z)) & 255;
if (z < zf) zf--; double dz = z - std::floor(z);
int Z = zf & 255; double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
z -= zf;
double w = z * z * z * (z * (z * 6 - 15) + 10);
A = p[X] + 0; int A = p[X];
AA = p[A] + Z; int AA = p[A] + Z;
B = p[X + 1] + 0; int B = p[X + 1];
BA = p[B] + Z; int 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));
double val = lerp(w, vv0, vv2); 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[pp++] += val * scale; buffer[idx++] += lerp(w, v0, v2) * invPow;
} }
} }
return;
} }
int pp = 0; else
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;
for (int xx = 0; xx < xSize; xx++)
{ {
double x = _x + (xx) * xs + xo; // Ïîëíàÿ 3D âåðñèÿ ñ êýøèðîâàíèåì ïî Y
int xf = static_cast<int>(x); int yPrev = -1;
if (x < xf) xf--; int A, AA, AB, B, BA, BB;
int X = xf & 255; double vv0, vv1, vv2, vv3;
x -= xf;
double u = x * x * x * (x * (x * 6 - 15) + 10);
for (int xx = 0; xx < xSize; ++xx)
for (int zz = 0; zz < zSize; zz++)
{ {
double z = _z + (zz) * zs + zo; double x = _x + xx * xs + xo;
int zf = static_cast<int>(z); int X = static_cast<int>(std::floor(x)) & 255;
if (z < zf) zf--; double dx = x - std::floor(x);
int Z = zf & 255; double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
z -= zf;
double w = z * z * z * (z * (z * 6 - 15) + 10);
for (int zz = 0; zz < zSize; ++zz)
for (int yy = 0; yy < ySize; yy++)
{ {
double y = _y + (yy) * ys + yo; double z = _z + zz * zs + zo;
int yf = static_cast<int>(y); int Z = static_cast<int>(std::floor(z)) & 255;
if (y < yf) yf--; double dz = z - std::floor(z);
int Y = yf & 255; double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
y -= yf;
double v = y * y * y * (y * (y * 6 - 15) + 10);
if (yy == 0 || Y != yOld) for (int yy = 0; yy < ySize; ++yy)
{ {
yOld = Y; 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; A = p[X] + Y;
AA = p[A] + Z; AA = p[A] + Z;
AB = p[A + 1] + Z; AB = p[A + 1] + Z;
B = p[X + 1] + Y; B = p[X + 1] + Y;
BA = p[B] + Z; BA = p[B] + Z;
BB = p[B + 1] + 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));
}
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));
}
double v0 = lerp(v, vv0, vv1); double v0 = lerp(v, vv0, vv1);
double v1 = lerp(v, vv2, vv3); double v1 = lerp(v, vv2, vv3);
double val = lerp(w, v0, v1); buffer[idx++] += lerp(w, v0, v1) * invPow;
}
buffer[pp++] += val * scale;
} }
} }
} }

View file

@ -1,29 +1,28 @@
#pragma once #pragma once
#include "Synth.h" #include "Synth.h"
class ImprovedNoise : public Synth class ImprovedNoise : public Synth
{ {
friend class PerlinNoise_SPU; friend class PerlinNoise_SPU;
private: private:
int *p; int p[512]; // permutation table (size 512 for easy indexing)
double xo, yo, zo; // random offsets for each instance
public: public:
double scale;
double xo, yo, zo;
ImprovedNoise(); ImprovedNoise();
ImprovedNoise(Random *random); explicit ImprovedNoise(Random* random);
void init(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); void add(doubleArray buffer, double _x, double _y, double _z,
double grad2(int hash, double x, double z); int xSize, int ySize, int zSize,
double grad(int hash, double x, double y, double z); double xs, double ys, double zs, double pow) const;
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);
}; };

View file

@ -1,10 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "PerlinNoise.h" #include "PerlinNoise.h"
#include "Random.h"
#include "Mth.h" #include "Mth.h"
PerlinNoise::PerlinNoise(int levels) PerlinNoise::PerlinNoise(int levels)
{ {
Random random; Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
init(&random, levels); init(&random, levels);
} }
@ -18,7 +19,7 @@ void PerlinNoise::init(Random *random, int levels)
MemSect(2); MemSect(2);
this->levels = levels; this->levels = levels;
noiseLevels = new ImprovedNoise * [levels]; noiseLevels = new ImprovedNoise * [levels];
for (int i = 0; i < levels; i++) for (int i = 0; i < levels; ++i)
{ {
noiseLevels[i] = new ImprovedNoise(random); noiseLevels[i] = new ImprovedNoise(random);
} }
@ -27,72 +28,71 @@ void PerlinNoise::init(Random *random, int levels)
PerlinNoise::~PerlinNoise() PerlinNoise::~PerlinNoise()
{ {
for( int i = 0; i < levels; i++ ) for (int i = 0; i < levels; ++i)
{
delete noiseLevels[i]; delete noiseLevels[i];
}
delete[] noiseLevels; delete[] noiseLevels;
} }
double PerlinNoise::getValue(double x, double y) double PerlinNoise::getValue(double x, double y)
{ {
double value = 0; double value = 0.0;
double pow = 1; double amp = 1.0; // àìïëèòóäà (çäåñü 1/pow â îðèãèíàëå)
for (int i = 0; i < levels; ++i)
for (int i = 0; i < levels; i++)
{ {
value += noiseLevels[i]->getValue(x * pow, y * pow) / pow; value += noiseLevels[i]->getValue(x * amp, y * amp) / amp;
pow /= 2; amp *= 0.5; // óìåíüøàåì ÷àñòîòó (pow /= 2)
} }
return value; return value;
} }
double PerlinNoise::getValue(double x, double y, double z) double PerlinNoise::getValue(double x, double y, double z)
{ {
double value = 0; double value = 0.0;
double pow = 1; double amp = 1.0;
for (int i = 0; i < levels; ++i)
for (int i = 0; i < levels; i++)
{ {
value += noiseLevels[i]->getValue(x * pow, y * pow, z * pow) / pow; value += noiseLevels[i]->getValue(x * amp, y * amp, z * amp) / amp;
pow /= 2; amp *= 0.5;
} }
return value; 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++) if (buffer.data == nullptr)
buffer[i] = 0; buffer = doubleArray(xSize * ySize * zSize);
else
for (unsigned int i = 0; i < buffer.length; ++i)
buffer[i] = 0.0;
double freq = 1.0; // ÷àñòîòà (pow)
double pow = 1; for (int i = 0; i < levels; ++i)
for (int i = 0; i < levels; i++)
{ {
// value += noiseLevels[i].getValue(x * pow, y * pow, z * pow) / pow; // Âûçîâ add äëÿ òåêóùåãî óðîâíÿ ñ ïðàâèëüíûì ìàñøòàáèðîâàíèåì
double xx = x * pow * xScale; noiseLevels[i]->add(buffer,
double yy = y * pow * yScale; x * freq * xScale,
double zz = z * pow * zScale; y * freq * yScale,
int64_t xb = Mth::lfloor(xx); z * freq * zScale,
int64_t zb = Mth::lfloor(zz); xSize, ySize, zSize,
xx -= xb; xScale * freq,
zz -= zb; yScale * freq,
xb %= 16777216; zScale * freq,
zb %= 16777216; freq);
xx += xb; freq *= 0.5;
zz += zb;
noiseLevels[i]->add(buffer, xx, yy, zz, xSize, ySize, zSize, xScale * pow, yScale * pow, zScale * pow, pow);
pow /= 2;
} }
return buffer; 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 "Random.h"
#include "System.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() 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 // 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
@ -104,3 +290,4 @@ bool Random::nextBoolean()
{ {
return next(1) != 0; return next(1) != 0;
} }
#endif

View file

@ -1,5 +1,31 @@
#pragma once #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 class Random
{ {
private: private:
@ -21,3 +47,4 @@ public:
int64_t nextLong(); int64_t nextLong();
bool nextBoolean(); bool nextBoolean();
}; };
#endif