Skip to content

Commit

Permalink
fixes #23915; std/random produces different results on c/js (#24003)
Browse files Browse the repository at this point in the history
fixes #23915
  • Loading branch information
ringabout authored Aug 25, 2024
1 parent 4ef06a5 commit 0d53b6e
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 18 deletions.
45 changes: 32 additions & 13 deletions lib/pure/random.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 10 additions & 5 deletions tests/stdlib/trandom.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

0 comments on commit 0d53b6e

Please sign in to comment.