1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-11-13 04:39:36 +00:00
* RNG doc

* Add some missing note qualifiers in comments

* code_800FD970 -> rand in Makefile and disasm CSVs
This commit is contained in:
Tharo 2024-02-27 03:21:25 +00:00 committed by GitHub
parent 57ae8ae1dd
commit 7f64ace8f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 167 additions and 84 deletions

View file

@ -238,7 +238,7 @@ $(BUILD_DIR)/src/boot/stackcheck.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/__osMalloc.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/code_800FC620.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/code_800FCE80.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/code_800FD970.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/rand.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/gfxprint.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/jpegutils.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/jpegdecoder.o: OPTFLAGS := -O2

2
spec
View file

@ -482,7 +482,7 @@ beginseg
include "$(BUILD_DIR)/src/code/code_800FCE80.o"
include "$(BUILD_DIR)/src/code/fp.o"
include "$(BUILD_DIR)/src/code/system_malloc.o"
include "$(BUILD_DIR)/src/code/code_800FD970.o"
include "$(BUILD_DIR)/src/code/rand.o"
include "$(BUILD_DIR)/src/code/__osMalloc.o"
#if !OOT_DEBUG
include "$(BUILD_DIR)/src/libultra/libc/sprintf.o"

View file

@ -1,79 +0,0 @@
#include "global.h"
// The latest generated random number, used to generate the next number in the sequence.
static u32 sRandInt = 1;
// Space to store a value to be re-interpreted as a float.
static u32 sRandFloat;
/**
* Gets the next integer in the sequence of pseudo-random numbers.
*/
u32 Rand_Next(void) {
return sRandInt = (sRandInt * 1664525) + 1013904223;
}
/**
* Seeds the pseudo-random number generator by providing a starting value.
*/
void Rand_Seed(u32 seed) {
sRandInt = seed;
}
/**
* Returns a pseudo-random floating-point number between 0.0f and 1.0f, by generating
* the next integer and masking it to an IEEE-754 compliant floating-point number
* between 1.0f and 2.0f, returning the result subtract 1.0f.
*/
f32 Rand_ZeroOne(void) {
sRandInt = (sRandInt * 1664525) + 1013904223;
sRandFloat = ((sRandInt >> 9) | 0x3F800000);
return *((f32*)&sRandFloat) - 1.0f;
}
/**
* Returns a pseudo-random floating-point number between -0.5f and 0.5f by the same
* manner in which Rand_ZeroOne generates its result.
*/
f32 Rand_Centered(void) {
sRandInt = (sRandInt * 1664525) + 1013904223;
sRandFloat = ((sRandInt >> 9) | 0x3F800000);
return *((f32*)&sRandFloat) - 1.5f;
}
/**
* Seeds a pseudo-random number at rndNum with a provided seed.
*/
void Rand_Seed_Variable(u32* rndNum, u32 seed) {
*rndNum = seed;
}
/**
* Generates the next pseudo-random integer from the provided rndNum.
*/
u32 Rand_Next_Variable(u32* rndNum) {
return *rndNum = (*rndNum * 1664525) + 1013904223;
}
/**
* Generates the next pseudo-random floating-point number between 0.0f and
* 1.0f from the provided rndNum.
*/
f32 Rand_ZeroOne_Variable(u32* rndNum) {
u32 next = (*rndNum * 1664525) + 1013904223;
sRandFloat = ((*rndNum = next) >> 9) | 0x3F800000;
return *((f32*)&sRandFloat) - 1.0f;
}
/**
* Generates the next pseudo-random floating-point number between -0.5f and
* 0.5f from the provided rndNum.
*/
f32 Rand_Centered_Variable(u32* rndNum) {
u32 next = (*rndNum * 1664525) + 1013904223;
*rndNum = next;
sRandFloat = (next >> 9) | 0x3F800000;
return *((f32*)&sRandFloat) - 1.5f;
}

162
src/code/rand.c Normal file
View file

@ -0,0 +1,162 @@
/**
* @file rand.c
*
* This file implements the primary random number generator the game relies on. The generator is pseudo-random and
* implemented as a Linear Congruential Generator (LCG).
*
* A LCG computes random numbers sequentially via the relation
* X(n+1) = (a * X(n) + c) mod m
* where m is the modulus, a is the multiplier and c is the increment.
*
* These three parameters (a,c,m) completely specify the LCG and should be chosen such that
* - m > 0
* - 0 < a < m
* - 0 <= c < m
*
* The period of the LCG (a, c, m) is the smallest period p such that X(n + p) = X(n), past n=p the sequence will repeat
* itself in its outputs.
* A good LCG should have the maximum possible period, which will be equal to m as there are at most m possible values
* for X. This occurs when (Hull, T.E., & Dobell, A.R. (1962). Random Number Generators. Siam Review, 4, 230-254.):
* - m,c are relatively prime, that is the only integer that divides both m and c with no remainder is 1.
* - a - 1 is divisible by all prime factors of m.
* - a - 1 is divisible by 4 if m is divisible by 4.
*
* Ideally m is chosen to be a large power of 2 so that the modulo operation is inexpensive to compute. In this case the
* prime factors of m = 2^k are just k copies of 2. For k > 1 m is divisible by 4, so a - 1 must be divisible by 4. 2^k
* and c can easily be made relatively prime by making c an odd number.
* If we let k=32 to match the size of an integer, the modulo operation is made implicit by the width of the data type
* and becomes free to compute.
*
* The parameter a should be selected such that a-1 is divisible by 4 (and hence divisible by 2) and c should be any odd
* number. The precise values should fare well against the spectral test, a measure of "how random" a particular LCG is.
* A pair (a,c) that satisfies these requirements is (1664525, 1013904223), recommended by "Numerical Recipes in C: The
* Art of Scientific Computing" (p. 284).
*
* Therefore, the LCG with parameters (1664525, 1013904223, 2^32) that is implemented in this file has a maximal period
* of 2^32 and produces high-quality pseudo-random numbers.
*
* @note If sampling the LCG for a n-bit number it is important to use the upper n bits instead of the lower n bits of
* the LCG output. The lower n bits only have a period of 2^n which may significantly worsen the quality of the
* resulting random numbers compared to the quality of the full 32-bit result.
*
* @note Original name: qrand.c
*/
#include "ultra64.h"
#define RAND_MULTIPLIER 1664525
#define RAND_INCREMENT 1013904223
/**
* The latest generated random number, used to generate the next number in the sequence.
*
* @note Original name: __qrand_idum
*/
static u32 sRandInt = 1;
/**
* Space to store a value to be re-interpreted as a float.
*
* @note Orignal name: __qrand_itemp
*/
static fu sRandFloat;
/**
* Gets the next integer in the sequence of pseudo-random numbers.
*
* @note Original name: qrand
*/
u32 Rand_Next(void) {
return sRandInt = sRandInt * RAND_MULTIPLIER + RAND_INCREMENT;
}
/**
* Seeds the pseudo-random number generator by providing a starting value.
*
* @note Original name: sqrand
*/
void Rand_Seed(u32 seed) {
sRandInt = seed;
}
/**
* Returns a pseudo-random floating-point number between 0.0f and 1.0f, by generating the next integer and masking it
* to an IEEE-754 compliant floating-point number between 1.0f and 2.0f, returning the result subtract 1.0f.
*
* @note This technique for generating pseudo-random floats is recommended as a particularly fast but potentially
* non-portable generator in "Numerical Recipes in C: The Art of Scientic Computing", pp. 284-5.
*
* @note Original name: fqrand
*/
f32 Rand_ZeroOne(void) {
sRandInt = sRandInt * RAND_MULTIPLIER + RAND_INCREMENT;
// Samples the upper 23 bits to avoid effectively reducing the LCG period.
sRandFloat.i = (sRandInt >> 9) | 0x3F800000;
return sRandFloat.f - 1.0f;
}
/**
* Returns a pseudo-random floating-point number between -0.5f and 0.5f by the same manner in which Rand_ZeroOne
* generates its result.
*
* @see Rand_ZeroOne
*
* @note Original name: fqrand2
*/
f32 Rand_Centered(void) {
sRandInt = sRandInt * RAND_MULTIPLIER + RAND_INCREMENT;
sRandFloat.i = (sRandInt >> 9) | 0x3F800000;
return sRandFloat.f - 1.5f;
}
//! All functions below are unused variants of the above four, that use a provided random number variable instead of the
//! internal `sRandInt`
/**
* Seeds a pseudo-random number at rndNum with a provided starting value.
*
* @see Rand_Seed
*
* @note Original name: sqrand_r
*/
void Rand_Seed_Variable(u32* rndNum, u32 seed) {
*rndNum = seed;
}
/**
* Generates the next pseudo-random integer from the provided rndNum.
*
* @see Rand_Next
*
* @note Original name: qrand_r
*/
u32 Rand_Next_Variable(u32* rndNum) {
return *rndNum = (*rndNum) * RAND_MULTIPLIER + RAND_INCREMENT;
}
/**
* Generates the next pseudo-random floating-point number between 0.0f and 1.0f from the provided rndNum.
*
* @see Rand_ZeroOne
*
* @note Original name: fqrand_r
*/
f32 Rand_ZeroOne_Variable(u32* rndNum) {
u32 next = (*rndNum) * RAND_MULTIPLIER + RAND_INCREMENT;
sRandFloat.i = ((*rndNum = next) >> 9) | 0x3F800000;
return sRandFloat.f - 1.0f;
}
/**
* Generates the next pseudo-random floating-point number between -0.5f and 0.5f from the provided rndNum.
*
* @see Rand_ZeroOne, Rand_Centered
*
* @note Original name: fqrand2_r
*/
f32 Rand_Centered_Variable(u32* rndNum) {
u32 next = (*rndNum) * RAND_MULTIPLIER + RAND_INCREMENT;
sRandFloat.i = ((*rndNum = next) >> 9) | 0x3F800000;
return sRandFloat.f - 1.5f;
}

View file

@ -132,7 +132,7 @@ BCBE0,800CDAE0,src/code/padsetup
BCD20,800CDC20,src/code/code_800FCE80
BD230,800CE130,src/code/fp
BD390,800CE290,src/code/system_malloc
BD560,800CE460,src/code/code_800FD970
BD560,800CE460,src/code/rand
BD720,800CE620,src/code/__osMalloc
BE4D0,800CF3D0,src/libultra/libc/sprintf
BE5A0,800CF4A0,src/code/printutils
@ -295,7 +295,7 @@ F0640,80101540,src/code/logseverity
F0650,80101550,src/code/gfxprint
F0F00,80101E00,src/code/code_800FC620
F0F20,80101E20,src/code/fp
F0F30,80101E30,src/code/code_800FD970
F0F30,80101E30,src/code/rand
F0F40,80101E40,src/code/__osMalloc
F0F50,80101E50,src/libultra/gu/sins
F1750,80102650,src/libultra/io/siacs
@ -451,7 +451,7 @@ offset,vram,.bss
119530,8012A430,src/code/gfxprint
119540,8012A440,src/code/code_800FCE80
119550,8012A450,src/code/system_malloc
119580,8012A480,src/code/code_800FD970
119580,8012A480,src/code/rand
119590,8012A490,src/code/__osMalloc
1195A0,8012A4A0,src/code/jpegdecoder
1195B0,8012A4B0,src/libultra/io/sptask

1 offset vram .text
132 BCD20 800CDC20 src/code/code_800FCE80
133 BD230 800CE130 src/code/fp
134 BD390 800CE290 src/code/system_malloc
135 BD560 800CE460 src/code/code_800FD970 src/code/rand
136 BD720 800CE620 src/code/__osMalloc
137 BE4D0 800CF3D0 src/libultra/libc/sprintf
138 BE5A0 800CF4A0 src/code/printutils
295 F0F00 80101E00 src/code/code_800FC620
296 F0F20 80101E20 src/code/fp
297 F0F30 80101E30 src/code/code_800FD970 src/code/rand
298 F0F40 80101E40 src/code/__osMalloc
299 F0F50 80101E50 src/libultra/gu/sins
300 F1750 80102650 src/libultra/io/siacs
301 F1760 80102660 src/libultra/io/controller
451 1195A0 8012A4A0 src/code/jpegdecoder
452 1195B0 8012A4B0 src/libultra/io/sptask
453 1195F0 8012A4F0 src/libultra/io/motor
454 1196F0 8012A5F0 src/libultra/io/siacs
455 119710 8012A610 src/libultra/io/controller
456 1197A0 8012A6A0 src/libultra/io/contpfs
457 1198A0 8012A7A0 src/libultra/io/pfsisplug