RNG improvements (replay-breaking)

This commit is contained in:
Andrei Alexeyev 2019-11-12 02:58:22 +02:00
parent 14a2d50edf
commit 35c1a90912
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
3 changed files with 58 additions and 15 deletions

View file

@ -87,17 +87,38 @@ uint64_t tsrand64(void) {
return tsrand64_p(tsrand_current);
}
static inline double makedouble(uint64_t x) {
// Range: [0..1)
return (x >> 11) * (1.0 / (UINT64_C(1) << 53));
static inline double make_unsigned_double(uint64_t x) {
// Range: [0.0; 1.0)
return (x >> 11) * 0x1.0p-53;
}
static inline double make_signed_double(uint64_t x) {
// Range: (-1.0; 1.0)
// NOTE: slight bias towards 0, because -0 exists
DoubleBits db;
db.val = make_unsigned_double(x << 1);
db.bits |= x & (UINT64_C(1) << 63);
return db.val;
}
double frand(void) {
return makedouble(tsrand64());
return make_unsigned_double(tsrand64());
}
double nfrand(void) {
return frand() * 2.0 - 1.0;
return make_signed_double(tsrand64());
}
bool rand_bool(void) {
return tsrand64() >> 63;
}
double rand_sign(void) {
return bits_to_double((UINT64_C(0x3FF) << 52) | (tsrand64() & (UINT64_C(1) << 63)));
}
float rand_signf(void) {
return bits_to_float((0x7f << 23) | (tsrand() & (1 << 31)));
}
// we use this to support multiple rands in a single statement without breaking replays across different builds
@ -157,11 +178,11 @@ uint32_t _tsrand_a(int idx, const char *file, uint line) {
}
double _afrand(int idx, const char *file, uint line) {
return makedouble(_tsrand64_a(idx, file, line));
return make_unsigned_double(_tsrand64_a(idx, file, line));
}
double _anfrand(int idx, const char *file, uint line) {
return _afrand(idx, file, line) * 2 - 1;
return make_signed_double(_tsrand64_a(idx, file, line));
}
void tsrand_lock(RandomState *rnd) {

View file

@ -32,8 +32,11 @@ uint64_t tsrand64(void);
void tsrand_lock(RandomState *rnd);
void tsrand_unlock(RandomState *rnd);
double frand(void);
double nfrand(void);
double frand(void); // Range: [0.0; 1.0)
double nfrand(void); // Range: (-1.0; 1.0)
bool rand_bool(void);
double rand_sign(void); // 1.0 or -1.0
float rand_signf(void); // 1.0f or -1.0f
void _tsrand_fill_p(RandomState *rnd, int amount, const char *file, uint line);
void _tsrand_fill(int amount, const char *file, uint line);
@ -50,6 +53,7 @@ double _anfrand(int idx, const char *file, uint line);
#define TSRAND_ARRAY_LIMIT 16
// Range: [rmin; rmax)
INLINE double rand_range(double rmin, double rmax) {
// TODO: ensure uniform distribution?
return frand() * (rmax - rmin) + rmin;
@ -60,4 +64,8 @@ INLINE double rand_angle(void) {
return frand() * (M_PI * 2);
}
INLINE bool rand_chance(double chance) {
return frand() < chance;
}
#endif // IGUARD_random_h

View file

@ -17,16 +17,30 @@ void* memdup(const void *src, size_t size) attr_returns_allocated attr_nonnull(1
void inherit_missing_pointers(uint num, void *dest[num], void *const base[num]) attr_nonnull(2, 3);
bool is_main_thread(void);
typedef union FloatBits {
float val;
uint32_t bits;
} FloatBits;
typedef union DoubleBits {
double val;
uint64_t bits;
} DoubleBits;
INLINE uint32_t float_to_bits(float f) {
union { uint32_t i; float f; } u;
u.f = f;
return u.i;
return ((FloatBits) { .val = f }).bits;
}
INLINE float bits_to_float(uint32_t i) {
union { uint32_t i; float f; } u;
u.i = i;
return u.f;
return ((FloatBits) { .bits = i }).val;
}
INLINE uint32_t double_to_bits(float f) {
return ((DoubleBits) { .val = f }).bits;
}
INLINE double bits_to_double(uint64_t i) {
return ((DoubleBits) { .bits = i }).val;
}
extern SDL_threadID main_thread_id;