diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h index f4d9c9fa8a..e4f8ad2504 100644 --- a/include/SDL3/SDL_stdinc.h +++ b/include/SDL3/SDL_stdinc.h @@ -1274,6 +1274,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STR * \since This function is available since SDL 3.0.0. * * \sa SDL_rand + * \sa SDL_rand_bits * \sa SDL_randf */ extern SDL_DECLSPEC void SDLCALL SDL_srand(Uint64 seed); @@ -1288,6 +1289,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_srand(Uint64 seed); * Example: to simulate a d6 use `SDL_rand(6) + 1` The +1 converts 0..5 to * 1..6 * + * If you want to generate a pseudo-random number in the full range of Sint32, you should use: (Sint32)SDL_rand_bits() + * * If you want reproducible output, be sure to initialize with SDL_srand() * first. * @@ -1332,6 +1335,29 @@ extern SDL_DECLSPEC Sint32 SDLCALL SDL_rand(Sint32 n); */ extern SDL_DECLSPEC float SDLCALL SDL_randf(void); +/** + * Generate 32 pseudo-random bits. + * + * You likely want to use SDL_rand() to get a psuedo-random number instead. + * + * There are no guarantees as to the quality of the random sequence produced, + * and this should not be used for security (cryptography, passwords) or where + * money is on the line (loot-boxes, casinos). There are many random number + * libraries available with different characteristics and you should pick one + * of those to meet any serious needs. + * + * \returns a random value in the range of [0-SDL_MAX_UINT32]. + * + * \threadsafety All calls should be made from a single thread + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_rand + * \sa SDL_randf + * \sa SDL_srand + */ +extern SDL_DECLSPEC Uint32 SDLCALL SDL_rand_bits(void); + /** * Generate a pseudo-random number less than n for positive n * @@ -1342,6 +1368,8 @@ extern SDL_DECLSPEC float SDLCALL SDL_randf(void); * Example: to simulate a d6 use `SDL_rand_r(state, 6) + 1` The +1 converts 0..5 to * 1..6 * + * If you want to generate a pseudo-random number in the full range of Sint32, you should use: (Sint32)SDL_rand_bits_r(state) + * * There are no guarantees as to the quality of the random sequence produced, * and this should not be used for security (cryptography, passwords) or where * money is on the line (loot-boxes, casinos). There are many random number @@ -1390,7 +1418,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_randf_r(Uint64 *state); /** * Generate 32 pseudo-random bits. * - * You likely want to use SDL_rand_r() to get a psuedo-randum number instead. + * You likely want to use SDL_rand_r() to get a psuedo-random number instead. * * There are no guarantees as to the quality of the random sequence produced, * and this should not be used for security (cryptography, passwords) or where diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 261f6c4e58..02fe914686 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -962,6 +962,7 @@ SDL3_0.0.0 { SDL_qsort; SDL_qsort_r; SDL_rand; + SDL_rand_bits; SDL_rand_bits_r; SDL_rand_r; SDL_randf; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index e3a1e4c90a..ba1777a373 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -987,6 +987,7 @@ #define SDL_qsort SDL_qsort_REAL #define SDL_qsort_r SDL_qsort_r_REAL #define SDL_rand SDL_rand_REAL +#define SDL_rand_bits SDL_rand_bits_REAL #define SDL_rand_bits_r SDL_rand_bits_r_REAL #define SDL_rand_r SDL_rand_r_REAL #define SDL_randf SDL_randf_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index f346730005..67e62d7b6b 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -996,6 +996,7 @@ SDL_DYNAPI_PROC(float,SDL_powf,(float a, float b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_qsort,(void *a, size_t b, size_t c, SDL_CompareCallback d),(a,b,c,d),) SDL_DYNAPI_PROC(void,SDL_qsort_r,(void *a, size_t b, size_t c, SDL_CompareCallback_r d, void *e),(a,b,c,d,e),) SDL_DYNAPI_PROC(Sint32,SDL_rand,(Sint32 a),(a),return) +SDL_DYNAPI_PROC(Uint32,SDL_rand_bits,(void),(),return) SDL_DYNAPI_PROC(Uint32,SDL_rand_bits_r,(Uint64 *a),(a),return) SDL_DYNAPI_PROC(Sint32,SDL_rand_r,(Uint64 *a, Sint32 b),(a,b),return) SDL_DYNAPI_PROC(float,SDL_randf,(void),(),return) diff --git a/src/stdlib/SDL_random.c b/src/stdlib/SDL_random.c index 1ad0b3ea59..9295d593ac 100644 --- a/src/stdlib/SDL_random.c +++ b/src/stdlib/SDL_random.c @@ -52,6 +52,15 @@ float SDL_randf(void) return SDL_randf_r(&SDL_rand_state); } +Uint32 SDL_rand_bits(void) +{ + if (!SDL_rand_initialized) { + SDL_srand(0); + } + + return SDL_rand_bits_r(&SDL_rand_state); +} + Uint32 SDL_rand_bits_r(Uint64 *state) { if (!state) { diff --git a/src/test/SDL_test_fuzzer.c b/src/test/SDL_test_fuzzer.c index 73fc07f1e3..991e2211f3 100644 --- a/src/test/SDL_test_fuzzer.c +++ b/src/test/SDL_test_fuzzer.c @@ -58,28 +58,35 @@ Uint8 SDLTest_RandomUint8(void) { fuzzerInvocationCounter++; - return (Uint8)SDL_rand_r(&rndContext, SDL_MAX_UINT8 + 1); + return (Uint8)(SDL_rand_bits_r(&rndContext) >> 24); } Sint8 SDLTest_RandomSint8(void) { fuzzerInvocationCounter++; - return (Sint8)SDL_rand_r(&rndContext, SDL_MAX_UINT8 + 1) ; + return (Sint8)(SDL_rand_bits_r(&rndContext) >> 24); } Uint16 SDLTest_RandomUint16(void) { fuzzerInvocationCounter++; - return (Uint16)SDL_rand_r(&rndContext, SDL_MAX_UINT16 + 1); + return (Uint16)(SDL_rand_bits_r(&rndContext) >> 16); } Sint16 SDLTest_RandomSint16(void) { fuzzerInvocationCounter++; - return (Sint16)SDL_rand_r(&rndContext, SDL_MAX_UINT16 + 1); + return (Sint16)(SDL_rand_bits_r(&rndContext) >> 16); +} + +Uint32 SDLTest_RandomUint32(void) +{ + fuzzerInvocationCounter++; + + return SDL_rand_bits_r(&rndContext); } Sint32 SDLTest_RandomSint32(void) @@ -89,13 +96,6 @@ Sint32 SDLTest_RandomSint32(void) return (Sint32)SDL_rand_bits_r(&rndContext); } -Uint32 SDLTest_RandomUint32(void) -{ - fuzzerInvocationCounter++; - - return (Uint32)SDL_rand_bits_r(&rndContext); -} - Uint64 SDLTest_RandomUint64(void) { union @@ -103,7 +103,6 @@ Uint64 SDLTest_RandomUint64(void) Uint64 v64; Uint32 v32[2]; } value; - value.v64 = 0; fuzzerInvocationCounter++; @@ -120,7 +119,6 @@ Sint64 SDLTest_RandomSint64(void) Uint64 v64; Uint32 v32[2]; } value; - value.v64 = 0; fuzzerInvocationCounter++; @@ -130,25 +128,23 @@ Sint64 SDLTest_RandomSint64(void) return (Sint64)value.v64; } -Sint32 SDLTest_RandomIntegerInRange(Sint32 pMin, Sint32 pMax) +Sint32 SDLTest_RandomIntegerInRange(Sint32 min, Sint32 max) { - Sint64 min = pMin; - Sint64 max = pMax; - Sint64 temp; - Sint64 number; + fuzzerInvocationCounter++; - if (pMin > pMax) { - temp = min; - min = max; - max = temp; - } else if (pMin == pMax) { - return (Sint32)min; + if (min == max) { + return min; } - number = SDLTest_RandomUint32(); - /* invocation count increment in preceding call */ + if (min > max) { + Sint32 temp = min; + min = max; + max = temp; + } - return (Sint32)((number % ((max + 1) - min)) + min); + Sint32 range = (max - min); + SDL_assert(range < SDL_MAX_SINT32); + return min + SDL_rand(range + 1); } /** @@ -408,33 +404,42 @@ Sint64 SDLTest_RandomSint64BoundaryValue(Sint64 boundary1, Sint64 boundary2, SDL float SDLTest_RandomUnitFloat(void) { - return SDLTest_RandomUint32() / (float)UINT_MAX; + return SDL_randf(); } float SDLTest_RandomFloat(void) { - return (float)(SDLTest_RandomUnitDouble() * 2.0 * (double)FLT_MAX - (double)(FLT_MAX)); -} + union + { + float f; + Uint32 v32; + } value; -double -SDLTest_RandomUnitDouble(void) -{ - return (double)(SDLTest_RandomUint64() >> 11) * (1.0 / 9007199254740992.0); -} - -double -SDLTest_RandomDouble(void) -{ - double r = 0.0; - double s = 1.0; do { - s /= UINT_MAX + 1.0; - r += (double)SDLTest_RandomSint32() * s; - } while (s > DBL_EPSILON); + value.v32 = SDLTest_RandomUint32(); + } while (SDL_isnanf(value.f) || SDL_isinff(value.f)); - fuzzerInvocationCounter++; + return value.f; +} - return r; +double SDLTest_RandomUnitDouble(void) +{ + return (double)(SDLTest_RandomUint64() >> (64-53)) * 0x1.0p-53; +} + +double SDLTest_RandomDouble(void) +{ + union + { + double d; + Uint64 v64; + } value; + + do { + value.v64 = SDLTest_RandomUint64(); + } while (SDL_isnan(value.d) || SDL_isinf(value.d)); + + return value.d; } char *SDLTest_RandomAsciiString(void) diff --git a/src/test/SDL_test_harness.c b/src/test/SDL_test_harness.c index 674d125de0..e306e4630d 100644 --- a/src/test/SDL_test_harness.c +++ b/src/test/SDL_test_harness.c @@ -81,9 +81,12 @@ char *SDLTest_GenerateRunSeed(const int length) /* Generate a random string of alphanumeric characters */ for (counter = 0; counter < length; counter++) { - char ch = (char)(SDL_rand_r(&randomContext, (91 - 48) + 1) + 48); - if (ch >= 58 && ch <= 64) { - ch = 65; + char ch; + int v = SDL_rand_r(&randomContext, 10 + 26); + if (v < 10) { + ch = (char)('0' + v); + } else { + ch = (char)('A' + v - 10); } seed[counter] = ch; } diff --git a/test/testqsort.c b/test/testqsort.c index 5b8eb5b2f4..8ea18c03f1 100644 --- a/test/testqsort.c +++ b/test/testqsort.c @@ -130,7 +130,7 @@ int main(int argc, char *argv[]) test_sort("reverse sorted", nums, arraylen); for (i = 0; i < arraylen; i++) { - nums[i] = SDL_rand_r(&seed, SDL_MAX_SINT32); + nums[i] = SDL_rand_r(&seed, 1000000); } test_sort("random sorted", nums, arraylen); }