4jcraft/Minecraft.World/Util/Random.cpp
2026-03-13 17:06:56 -05:00

92 lines
2.6 KiB
C++

#include "../Platform/stdafx.h"
#include "Random.h"
#include <ctime>
#include <cstdint> // for int64_t
#include "../Platform/System.h"
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 use QueryPerformanceCounter here instead
__int64 seed;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
seed = ts.tv_sec * 1000000000LL + ts.tv_nsec;
seed += 8682522807148012LL;
setSeed(seed);
}
Random::Random(__int64 seed) { setSeed(seed); }
void Random::setSeed(__int64 s) {
this->seed = (s ^ 0x5DEECE66DLL) & ((1LL << 48) - 1);
haveNextNextGaussian = false;
}
int Random::next(int bits) {
// 4jcraft, cast to uint64_t for modulo arithmethic
// overflow of int undefined, and its guaranteed here.
seed = ((uint64_t)seed * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1);
return (int)(seed >> (48 - bits));
}
void Random::nextBytes(uint8_t* bytes, unsigned int count) {
for (unsigned int i = 0; i < count; i++) {
bytes[i] = (uint8_t)next(8);
}
}
double Random::nextDouble() {
return (((__int64)next(26) << 27) + next(27)) / (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) {
assert(n > 0);
if ((n & -n) == n) // i.e., n is a power of 2
// 4jcraft added casts to unsigned (and uint64_t)
return (int)(((uint64_t)next(31) * n) >>
31); // 4J Stu - Made __int64 instead of long
int bits, val;
do {
bits = next(31);
val = bits % n;
// 4jcraft added a cast to prevent overflow
} while ((int64_t)bits - val + (n - 1) < 0);
return val;
}
float Random::nextFloat() { return next(24) / ((float)(1 << 24)); }
__int64 Random::nextLong() {
// 4jcraft added casts to unsigned
return (int64_t)((uint64_t)next(32) << 32) + next(32);
}
bool Random::nextBoolean() { return next(1) != 0; }