From 0d53b6e027a66bc60ca853d57c019338bb73ba0b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 26 Aug 2024 04:23:30 +0800 Subject: [PATCH] fixes #23915; std/random produces different results on c/js (#24003) fixes #23915 --- lib/pure/random.nim | 45 ++++++++++++++++++++++++++++------------ tests/stdlib/trandom.nim | 15 +++++++++----- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 74994437629a..3ec77d37ee24 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -79,15 +79,28 @@ when defined(nimPreviewSlimSystem): include system/inclrtl {.push debugger: off.} +template whenHasBigInt64(yes64, no64): untyped = + when defined(js): + when compiles(compileOption("jsbigint64")): + when compileOption("jsbigint64"): + yes64 + else: + no64 + else: + no64 + else: + yes64 -when defined(js): - type Ui = uint32 - const randMax = 4_294_967_295u32 -else: +whenHasBigInt64: type Ui = uint64 const randMax = 18_446_744_073_709_551_615u64 +do: + type Ui = uint32 + + const randMax = 4_294_967_295u32 + type Rand* = object ## State of a random number generator. @@ -105,17 +118,17 @@ type ## generator are **not** thread-safe! a0, a1: Ui -when defined(js): - var state = Rand( - a0: 0x69B4C98Cu32, - a1: 0xFED1DD30u32) # global for backwards compatibility -else: +whenHasBigInt64: const DefaultRandSeed = Rand( a0: 0x69B4C98CB8530805u64, a1: 0xFED1DD3004688D67CAu64) # racy for multi-threading but good enough for now: var state = DefaultRandSeed # global for backwards compatibility +do: + var state = Rand( + a0: 0x69B4C98Cu32, + a1: 0xFED1DD30u32) # global for backwards compatibility func isValid(r: Rand): bool {.inline.} = ## Check whether state of `r` is valid. @@ -208,10 +221,10 @@ proc skipRandomNumbers*(s: var Rand) = doAssert vals == [501737, 497901, 500683, 500157] - when defined(js): - const helper = [0xbeac0467u32, 0xd86b048bu32] - else: + whenHasBigInt64: const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64] + do: + const helper = [0xbeac0467u32, 0xd86b048bu32] var s0 = Ui 0 s1 = Ui 0 @@ -294,7 +307,13 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} = let x = next(r) when defined(js): - result = (float(x) / float(high(uint32))) * max + when compiles(compileOption("jsbigint64")): + when compileOption("jsbigint64"): + result = (float(x) / float(high(uint64))) * max + else: + result = (float(x) / float(high(uint32))) * max + else: + result = (float(x) / float(high(uint32))) * max else: let u = (0x3FFu64 shl 52u64) or (x shr 12u64) result = (cast[float](u) - 1.0) * max diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index bec75c1ebd9c..eb32f7757569 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -47,6 +47,8 @@ block: type DiceRoll = range[0..6] when not defined(js): doAssert rand(DiceRoll).int == 3 + elif compileOption("jsbigint64"): + doAssert rand(DiceRoll).int == 1 else: doAssert rand(DiceRoll).int == 6 @@ -296,10 +298,13 @@ block: # bug #22360 else: inc fc - when defined(js): - when compileOption("jsbigint64"): - doAssert (tc, fc) == (517, 483), $(tc, fc) - else: - doAssert (tc, fc) == (515, 485), $(tc, fc) + when defined(js) and not compileOption("jsbigint64"): + doAssert (tc, fc) == (515, 485), $(tc, fc) else: doAssert (tc, fc) == (510, 490), $(tc, fc) + +block: + when defined(js) and not compileOption("jsbigint64"): + doAssert rand(int32.high) == 335507522 + else: + doAssert rand(int32.high) == 607539621