[libc-commits] [libc] [libc] Change rand implementation so all tests pass in both 32- and 64-bit systems (PR #98692)

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Fri Jul 12 13:36:53 PDT 2024


https://github.com/mikhailramalho created https://github.com/llvm/llvm-project/pull/98692

The current xorshift star algorithm fails to produce uniform enough values in 32-bit systems, so this patch changes the algorithm so the tests now pass in both 32- and 64-bit systems.

The multiplier used in the algorithm was obtained from "The Art of Computer Programming" book. It is also used by musl and newlib.

>From 3681378d593375a120904744d2714cc929aa7f78 Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Fri, 12 Jul 2024 17:32:17 -0300
Subject: [PATCH] [libc] Change rand implementation so all tests pass in both
 32- and 64-bit systems

The current xorshift star algorithm fails to produce uniform enough
values in 32-bit systems, so this patch changes the algorithm so the
tests now pass in both 32- and 64-bit systems.

The multiplifier used in the algorithm was obtained from "The Art of Computer
Programming" book. It is also used by musl and newlib.
---
 libc/src/stdlib/rand.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libc/src/stdlib/rand.cpp b/libc/src/stdlib/rand.cpp
index ff3875c2f6959..a38d3af7b8aaa 100644
--- a/libc/src/stdlib/rand.cpp
+++ b/libc/src/stdlib/rand.cpp
@@ -13,18 +13,18 @@
 
 namespace LIBC_NAMESPACE {
 
-// An implementation of the xorshift64star pseudo random number generator. This
-// is a good general purpose generator for most non-cryptographics applications.
+// This multiplier was obtained from Knuth, D.E., "The Art of
+// Computer Programming," Vol 2, Seminumerical Algorithms, Third
+// Edition, Addison-Wesley, 1998, p. 106 (line 26) & p. 108 */
 LLVM_LIBC_FUNCTION(int, rand, (void)) {
   unsigned long orig = rand_next.load(cpp::MemoryOrder::RELAXED);
   for (;;) {
-    unsigned long x = orig;
-    x ^= x >> 12;
-    x ^= x << 25;
-    x ^= x >> 27;
-    if (rand_next.compare_exchange_strong(orig, x, cpp::MemoryOrder::ACQUIRE,
+    uint64_t x = orig;
+    x = static_cast<unsigned long>(6364136223846793005ULL) * x;
+    if (rand_next.compare_exchange_strong(orig, static_cast<unsigned long>(x),
+                                          cpp::MemoryOrder::ACQUIRE,
                                           cpp::MemoryOrder::RELAXED))
-      return static_cast<int>((x * 0x2545F4914F6CDD1Dul) >> 32) & RAND_MAX;
+      return static_cast<int>(x >> 32) & RAND_MAX;
     sleep_briefly();
   }
 }



More information about the libc-commits mailing list