From 86db61ca30e0507c85c755342428a215f171eece Mon Sep 17 00:00:00 2001 From: Achraf Reyani Date: Fri, 9 Oct 2026 20:49:16 +0900 Subject: [PATCH] feat(libc): implement rand_r Share rand's generator step with rand_r, which advances the caller's state instead of the global one, as FreeBSD's rand and rand_r share do_rand. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libc/src/Math.cpp | 20 ++++++++++++++++---- core/libs/tests/GuestMath.cpp | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/core/libs/prx/libc/src/Math.cpp b/core/libs/prx/libc/src/Math.cpp index 8beda4557..992f358e3 100644 --- a/core/libs/prx/libc/src/Math.cpp +++ b/core/libs/prx/libc/src/Math.cpp @@ -127,15 +127,27 @@ int APS5_VABI __signbitf_nid_postfix(float x) { return std::signbit(x) ? 1 : 0; static std::mutex g_randLock; static std::uint32_t g_randState = 1; -int APS5_VABI rand_nid_postfix() { - std::lock_guard lock(g_randLock); - const std::int64_t x = static_cast(g_randState % 0x7ffffffeu) + 1; +static int NextRand_nid_no_patch(std::uint32_t& state) { + const std::int64_t x = static_cast(state % 0x7ffffffeu) + 1; std::int64_t next = 16807 * (x % 127773) - 2836 * (x / 127773); if (next < 0) next += 0x7fffffff; - g_randState = static_cast(next - 1); + state = static_cast(next - 1); return static_cast(next - 1); } +int APS5_VABI rand_nid_postfix() { + std::lock_guard lock(g_randLock); + return NextRand_nid_no_patch(g_randState); +} + +int APS5_VABI rand_r_nid_postfix(unsigned int* state) { + if (state == nullptr) throw std::invalid_argument("rand_r: null state"); + std::uint32_t value = *state; + const int result = NextRand_nid_no_patch(value); + *state = value; + return result; +} + void APS5_VABI srand_nid_postfix(unsigned int seed) { std::lock_guard lock(g_randLock); g_randState = seed; diff --git a/core/libs/tests/GuestMath.cpp b/core/libs/tests/GuestMath.cpp index b0a96e78b..ae2333740 100644 --- a/core/libs/tests/GuestMath.cpp +++ b/core/libs/tests/GuestMath.cpp @@ -35,6 +35,9 @@ float APS5_VABI atan2f_nid_postfix(float, float); float APS5_VABI hypotf_nid_postfix(float, float); double APS5_VABI hypot_nid_postfix(double, double); float APS5_VABI tanf_nid_postfix(float); +int APS5_VABI rand_nid_postfix(); +void APS5_VABI srand_nid_postfix(unsigned int); +int APS5_VABI rand_r_nid_postfix(unsigned int*); float APS5_VABI log10f_nid_postfix(float); float APS5_VABI logbf_nid_postfix(float); double APS5_VABI exp2_nid_postfix(double); @@ -234,6 +237,18 @@ int main() { Require(std::abs(acosf_nid_postfix(0.5f) - 1.0471976f) < 0.000001f); Require(std::abs(atan2f_nid_postfix(1.f, -1.f) - 2.3561945f) < 0.000001f); Require(tanf_nid_postfix(0.f) == 0.f); + unsigned int randomState = 1; + Require(rand_r_nid_postfix(&randomState) == 33613 && randomState == 33613u); + randomState = 0; + Require(rand_r_nid_postfix(&randomState) == 16806 && randomState == 16806u); + for (const unsigned int seed : {0u, 1u, 12345u, 0x7ffffffeu, 0xffffffffu}) { + srand_nid_postfix(seed); + randomState = seed; + for (int step = 0; step < 8; ++step) Require(rand_r_nid_postfix(&randomState) == rand_nid_postfix()); + } + bool threw = false; + try { rand_r_nid_postfix(nullptr); } catch (...) { threw = true; } + Require(threw); Require(hypot_nid_postfix(3.0, 4.0) == 5.0 && hypot_nid_postfix(-3.0, -4.0) == 5.0 && hypotf_nid_postfix(3.f, -4.f) == 5.f); Require(std::abs(hypot_nid_postfix(1e308, 1e308) / 1.4142135623730951e308 - 1.0) < 1e-15); Require(std::abs(hypotf_nid_postfix(2e38f, 2e38f) / 2.8284271e38f - 1.f) < 1e-6f);