feat(libc): implement erand48, nrand48 and jrand48

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Achraf ReyaniandClaude Opus 5.5 committed 2026-10-11 19:02:32 +09:00
1 parent 24cb0d2412
commit f85ae8d6f2
2 files changed
+62

No files matched your search

+27
View File
@@ -1,10 +1,12 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <array>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <mutex>
#include <stdexcept>
#include <string>
namespace {
@@ -93,10 +95,35 @@ void SaveTypeWordLocked() {
StoreWord(state.table, 0, static_cast<std::uint32_t>(word));
}
std::uint64_t NextRand48(std::uint16_t* seed, const char* function) {
if (seed == nullptr) throw std::invalid_argument(std::string(function) + ": null seed");
constexpr std::uint64_t Multiplier = 0x5deece66dull;
constexpr std::uint64_t Addend = 0xb;
constexpr std::uint64_t Mask = (1ull << 48) - 1;
std::uint64_t value = (static_cast<std::uint64_t>(seed[2]) << 32) | (static_cast<std::uint64_t>(seed[1]) << 16) | seed[0];
value = (value * Multiplier + Addend) & Mask;
seed[0] = static_cast<std::uint16_t>(value);
seed[1] = static_cast<std::uint16_t>(value >> 16);
seed[2] = static_cast<std::uint16_t>(value >> 32);
return value;
}
}
extern "C" {
double APS5_VABI erand48_nid_postfix(std::uint16_t* seed) {
return std::ldexp(static_cast<double>(NextRand48(seed, __func__)), -48);
}
std::int64_t APS5_VABI nrand48_nid_postfix(std::uint16_t* seed) {
return static_cast<std::int64_t>(NextRand48(seed, __func__) >> 17);
}
std::int64_t APS5_VABI jrand48_nid_postfix(std::uint16_t* seed) {
return static_cast<std::int32_t>(static_cast<std::uint32_t>(NextRand48(seed, __func__) >> 16));
}
std::int64_t APS5_VABI random_nid_postfix() {
std::lock_guard lock(g_randomLock);
return static_cast<std::int64_t>(NextLocked());
+35
View File
@@ -4,6 +4,7 @@
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <thread>
@@ -15,6 +16,9 @@ void APS5_VABI srandom_nid_postfix(std::uint64_t);
char* APS5_VABI initstate_nid_postfix(std::uint64_t, char*, std::int64_t);
char* APS5_VABI setstate_nid_postfix(char*);
int* APS5_VABI __error_nid_postfix();
double APS5_VABI erand48_nid_postfix(std::uint16_t*);
std::int64_t APS5_VABI nrand48_nid_postfix(std::uint16_t*);
std::int64_t APS5_VABI jrand48_nid_postfix(std::uint16_t*);
}
static int failures = 0;
@@ -40,7 +44,38 @@ static std::uint32_t Word(const char* table, std::size_t index) {
return value;
}
static bool SeedIs(const std::uint16_t* seed, std::uint16_t low, std::uint16_t middle, std::uint16_t high) {
return seed[0] == low && seed[1] == middle && seed[2] == high;
}
static void CheckRand48() {
std::uint16_t seed[3] = {0x330e, 0xabcd, 0x1234};
Require(erand48_nid_postfix(seed) == 0x657eb7255101p-48 && SeedIs(seed, 0x5101, 0xb725, 0x657e), "erand48 first value");
Require(nrand48_nid_postfix(seed) == 1804928587 && SeedIs(seed, 0x6378, 0x0c96, 0xd72a), "nrand48 second value");
Require(jrand48_nid_postfix(seed) == 1517566982 && SeedIs(seed, 0x2a23, 0x3c06, 0x5a74), "jrand48 third value");
Require(erand48_nid_postfix(seed) == 0x72534abf62f2p-48 && SeedIs(seed, 0x62f2, 0x4abf, 0x7253), "erand48 fourth value");
Require(nrand48_nid_postfix(seed) == 684387517 && SeedIs(seed, 0x8d15, 0xd97a, 0x5195), "nrand48 fifth value");
Require(jrand48_nid_postfix(seed) == -487786166 && SeedIs(seed, 0xeffc, 0xf94a, 0xe2ec), "jrand48 negative value");
std::uint16_t zero[3] = {};
Require(nrand48_nid_postfix(zero) == 0 && SeedIs(zero, 0x000b, 0, 0), "rand48 zero seed adds the increment");
std::uint16_t top[3] = {0xffff, 0xffff, 0xffff};
const double value = erand48_nid_postfix(top);
Require(value >= 0.0 && value < 1.0, "erand48 stays below 1");
#ifndef _WIN32
std::uint16_t guest[3] = {0x1234, 0x5678, 0x9abc};
unsigned short host[3] = {0x1234, 0x5678, 0x9abc};
for (int round = 0; round < 64; ++round) {
Require(erand48_nid_postfix(guest) == ::erand48(host), "erand48 matches the host");
Require(nrand48_nid_postfix(guest) == ::nrand48(host), "nrand48 matches the host");
Require(jrand48_nid_postfix(guest) == ::jrand48(host), "jrand48 matches the host");
}
#endif
}
int main() {
CheckRand48();
constexpr Sequence seedOne {1408992891, 1638182910, 83848093, 145962118, 627851256};
constexpr Sequence seed12345 {1052984060, 1639322404, 1971525204, 2097956667, 2012147915};
constexpr std::array<Sequence, 5> seed42ByType {{