SDL: Updated based on feedback from @JKaniarz

From 2f5b20fcb5f24531ce27784a8c466ba21038562e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 24 Jun 2024 08:28:14 -0700
Subject: [PATCH] Updated based on feedback from @JKaniarz

---
 include/SDL3/SDL_stdinc.h         | 30 +++++++++++-
 src/dynapi/SDL_dynapi.sym         |  1 +
 src/dynapi/SDL_dynapi_overrides.h |  1 +
 src/dynapi/SDL_dynapi_procs.h     |  1 +
 src/stdlib/SDL_random.c           |  9 ++++
 src/test/SDL_test_fuzzer.c        | 81 ++++++++++++++++---------------
 src/test/SDL_test_harness.c       |  9 ++--
 test/testqsort.c                  |  2 +-
 8 files changed, 91 insertions(+), 43 deletions(-)

diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h
index f4d9c9fa8a239..e4f8ad25042b6 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 261f6c4e5899b..02fe914686724 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 e3a1e4c90af3a..ba1777a3731f7 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 f3467300052e2..67e62d7b6bf6a 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 1ad0b3ea59212..9295d593ac0d2 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 73fc07f1e36c6..991e2211f3a67 100644
--- a/src/test/SDL_test_fuzzer.c
+++ b/src/test/SDL_test_fuzzer.c
@@ -58,42 +58,42 @@ 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);
 }
 
-Sint32 SDLTest_RandomSint32(void)
+Uint32 SDLTest_RandomUint32(void)
 {
     fuzzerInvocationCounter++;
 
-    return (Sint32)SDL_rand_bits_r(&rndContext);
+    return SDL_rand_bits_r(&rndContext);
 }
 
-Uint32 SDLTest_RandomUint32(void)
+Sint32 SDLTest_RandomSint32(void)
 {
     fuzzerInvocationCounter++;
 
-    return (Uint32)SDL_rand_bits_r(&rndContext);
+    return (Sint32)SDL_rand_bits_r(&rndContext);
 }
 
 Uint64 SDLTest_RandomUint64(void)
@@ -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 (min == max) {
+        return min;
+    }
 
-    if (pMin > pMax) {
-        temp = min;
+    if (min > max) {
+        Sint32 temp = min;
         min = max;
         max = temp;
-    } else if (pMin == pMax) {
-        return (Sint32)min;
     }
 
-    number = SDLTest_RandomUint32();
-    /* invocation count increment in preceding call */
-
-    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;
+
+    do {
+        value.v32 = SDLTest_RandomUint32();
+    } while (SDL_isnanf(value.f) || SDL_isinff(value.f));
+
+    return value.f;
 }
 
-double
-SDLTest_RandomUnitDouble(void)
+double SDLTest_RandomUnitDouble(void)
 {
-    return (double)(SDLTest_RandomUint64() >> 11) * (1.0 / 9007199254740992.0);
+    return (double)(SDLTest_RandomUint64() >> (64-53)) * 0x1.0p-53;
 }
 
-double
-SDLTest_RandomDouble(void)
+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);
+    union
+    {
+        double d;
+        Uint64 v64;
+    } value;
 
-    fuzzerInvocationCounter++;
+    do {
+        value.v64 = SDLTest_RandomUint64();
+    } while (SDL_isnan(value.d) || SDL_isinf(value.d));
 
-    return r;
+    return value.d;
 }
 
 char *SDLTest_RandomAsciiString(void)
diff --git a/src/test/SDL_test_harness.c b/src/test/SDL_test_harness.c
index 674d125de0df7..e306e4630d4de 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 5b8eb5b2f4c26..8ea18c03f1c6f 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);
     }