aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2023-06-06 09:43:20 -0400
committerGopher Robot <gobot@golang.org>2023-10-30 17:08:37 +0000
commitc26658784622e486c828c58403f0a58941d1e856 (patch)
tree3adadf78c3976db2a5abcfb79554ca028cf01c7a
parentc7dddb02d334e25d4cb7c227f2eaeaffd0d88a23 (diff)
downloadgo-c26658784622e486c828c58403f0a58941d1e856.tar.gz
go-c26658784622e486c828c58403f0a58941d1e856.zip
math/rand/v2: add, optimize N, UintN, Uint32N, Uint64N
Now that we can break the value stream, we can take advantage of better algorithms that have been suggested since the original code was written. Also optimizes IntN, Int32N, Int64N, Perm (indirectly). All the N variants (IntN, Int32N, Int64N, UintN, N, etc) now return the same values given a Source and parameter n, so that for example uint(r.IntN(10)) and r.UintN(10) and r.N(uint(10)) are completely interchangeable. Int64N4e18 gets slower but that is a near worst case for the algorithm and is extremely unlikely in practice. 32-bit Int32N variants got slower too, by 15-30%, in exchange for speeding up everything on 64-bit systems and consistency across the N functions. Also rename previously missed benchmark GlobalInt63Parallel to GlobalInt64Parallel. goos: linux goarch: amd64 pkg: math/rand/v2 cpu: AMD Ryzen 9 7950X 16-Core Processor │ 11ad9fdddc.amd64 │ 4d84a369d1.amd64 │ │ sec/op │ sec/op vs base │ SourceUint64-32 1.335n ± 1% 1.348n ± 2% ~ (p=0.335 n=20) GlobalInt64-32 2.046n ± 1% 2.082n ± 2% ~ (p=0.310 n=20) GlobalInt63Parallel-32 0.1037n ± 1% GlobalInt64Parallel-32 0.1036n ± 1% GlobalUint64-32 2.075n ± 0% 2.077n ± 2% ~ (p=0.228 n=20) GlobalUint64Parallel-32 0.1013n ± 1% 0.1012n ± 1% ~ (p=0.878 n=20) Int64-32 1.726n ± 2% 1.750n ± 0% +1.39% (p=0.000 n=20) Uint64-32 1.673n ± 1% 1.707n ± 2% +2.03% (p=0.002 n=20) GlobalIntN1000-32 3.895n ± 2% 3.192n ± 1% -18.05% (p=0.000 n=20) IntN1000-32 3.403n ± 1% 2.462n ± 2% -27.65% (p=0.000 n=20) Int64N1000-32 3.053n ± 2% 2.470n ± 1% -19.11% (p=0.000 n=20) Int64N1e8-32 2.718n ± 1% 2.503n ± 2% -7.91% (p=0.000 n=20) Int64N1e9-32 2.712n ± 1% 2.487n ± 1% -8.31% (p=0.000 n=20) Int64N2e9-32 2.690n ± 1% 2.487n ± 1% -7.57% (p=0.000 n=20) Int64N1e18-32 3.084n ± 2% 3.006n ± 2% -2.53% (p=0.000 n=20) Int64N2e18-32 4.026n ± 1% 3.368n ± 1% -16.33% (p=0.000 n=20) Int64N4e18-32 4.049n ± 2% 4.763n ± 1% +17.62% (p=0.000 n=20) Int32N1000-32 2.730n ± 0% 2.403n ± 1% -11.94% (p=0.000 n=20) Int32N1e8-32 2.916n ± 2% 2.405n ± 1% -17.53% (p=0.000 n=20) Int32N1e9-32 3.375n ± 1% 2.402n ± 2% -28.83% (p=0.000 n=20) Int32N2e9-32 3.292n ± 1% 2.384n ± 1% -27.58% (p=0.000 n=20) Float32-32 2.673n ± 1% 2.641n ± 2% ~ (p=0.147 n=20) Float64-32 2.485n ± 1% 2.483n ± 1% ~ (p=0.804 n=20) ExpFloat64-32 3.577n ± 2% 3.486n ± 2% -2.57% (p=0.000 n=20) NormFloat64-32 3.797n ± 2% 3.648n ± 1% -3.92% (p=0.000 n=20) Perm3-32 35.79n ± 2% 33.04n ± 1% -7.68% (p=0.000 n=20) Perm30-32 205.1n ± 1% 171.9n ± 1% -16.14% (p=0.000 n=20) Perm30ViaShuffle-32 111.2n ± 2% 100.3n ± 1% -9.76% (p=0.000 n=20) ShuffleOverhead-32 100.5n ± 2% 102.5n ± 1% +1.99% (p=0.007 n=20) Concurrent-32 2.188n ± 5% 2.101n ± 0% ~ (p=0.013 n=20) goos: darwin goarch: arm64 pkg: math/rand/v2 cpu: Apple M1 │ 11ad9fdddc.arm64 │ 4d84a369d1.arm64 │ │ sec/op │ sec/op vs base │ SourceUint64-8 2.272n ± 1% 2.261n ± 1% ~ (p=0.172 n=20) GlobalInt64-8 2.155n ± 1% 2.160n ± 1% ~ (p=0.482 n=20) GlobalInt63Parallel-8 0.4352n ± 0% GlobalInt64Parallel-8 0.4299n ± 0% GlobalUint64-8 2.173n ± 1% 2.169n ± 1% ~ (p=0.262 n=20) GlobalUint64Parallel-8 0.4340n ± 0% 0.4293n ± 1% -1.08% (p=0.000 n=20) Int64-8 2.544n ± 1% 2.473n ± 1% -2.83% (p=0.000 n=20) Uint64-8 2.552n ± 1% 2.453n ± 1% -3.90% (p=0.000 n=20) GlobalIntN1000-8 3.856n ± 0% 2.814n ± 2% -27.02% (p=0.000 n=20) IntN1000-8 3.820n ± 0% 2.933n ± 2% -23.22% (p=0.000 n=20) Int64N1000-8 3.219n ± 2% 2.934n ± 2% -8.85% (p=0.000 n=20) Int64N1e8-8 3.221n ± 2% 2.935n ± 2% -8.91% (p=0.000 n=20) Int64N1e9-8 3.276n ± 2% 2.934n ± 2% -10.44% (p=0.000 n=20) Int64N2e9-8 3.217n ± 0% 2.935n ± 2% -8.78% (p=0.000 n=20) Int64N1e18-8 3.502n ± 2% 3.778n ± 1% +7.91% (p=0.000 n=20) Int64N2e18-8 4.968n ± 1% 4.359n ± 1% -12.26% (p=0.000 n=20) Int64N4e18-8 4.963n ± 0% 6.546n ± 1% +31.92% (p=0.000 n=20) Int32N1000-8 3.189n ± 1% 2.940n ± 2% -7.81% (p=0.000 n=20) Int32N1e8-8 3.514n ± 1% 2.937n ± 2% -16.41% (p=0.000 n=20) Int32N1e9-8 4.133n ± 0% 2.938n ± 0% -28.91% (p=0.000 n=20) Int32N2e9-8 4.137n ± 0% 2.938n ± 2% -28.97% (p=0.000 n=20) Float32-8 3.468n ± 1% 3.486n ± 0% +0.52% (p=0.000 n=20) Float64-8 3.478n ± 0% 3.480n ± 0% ~ (p=0.063 n=20) ExpFloat64-8 4.563n ± 0% 4.533n ± 0% -0.67% (p=0.000 n=20) NormFloat64-8 4.768n ± 0% 4.764n ± 0% -0.07% (p=0.001 n=20) Perm3-8 28.94n ± 0% 26.66n ± 0% -7.88% (p=0.000 n=20) Perm30-8 175.9n ± 0% 143.4n ± 0% -18.50% (p=0.000 n=20) Perm30ViaShuffle-8 152.6n ± 1% 142.9n ± 0% -6.29% (p=0.000 n=20) ShuffleOverhead-8 119.6n ± 1% 120.7n ± 0% +0.96% (p=0.000 n=20) Concurrent-8 2.452n ± 3% 2.360n ± 2% -3.73% (p=0.007 n=20) goos: linux goarch: 386 pkg: math/rand/v2 cpu: AMD Ryzen 9 7950X 16-Core Processor │ 11ad9fdddc.386 │ 4d84a369d1.386 │ │ sec/op │ sec/op vs base │ SourceUint64-32 2.091n ± 1% 2.101n ± 2% ~ (p=0.672 n=20) GlobalInt64-32 3.514n ± 2% 3.518n ± 2% ~ (p=0.723 n=20) GlobalInt63Parallel-32 0.3197n ± 0% GlobalInt64Parallel-32 0.3206n ± 0% GlobalUint64-32 3.542n ± 1% 3.538n ± 1% ~ (p=0.304 n=20) GlobalUint64Parallel-32 0.3218n ± 0% 0.3231n ± 0% ~ (p=0.071 n=20) Int64-32 2.552n ± 2% 2.554n ± 2% ~ (p=0.693 n=20) Uint64-32 2.566n ± 1% 2.575n ± 2% ~ (p=0.606 n=20) GlobalIntN1000-32 5.965n ± 2% 6.292n ± 1% +5.46% (p=0.000 n=20) IntN1000-32 4.652n ± 1% 4.735n ± 1% +1.77% (p=0.000 n=20) Int64N1000-32 14.485n ± 1% 5.489n ± 2% -62.11% (p=0.000 n=20) Int64N1e8-32 14.675n ± 1% 5.528n ± 2% -62.33% (p=0.000 n=20) Int64N1e9-32 16.805n ± 2% 5.438n ± 2% -67.64% (p=0.000 n=20) Int64N2e9-32 14.515n ± 1% 5.474n ± 1% -62.28% (p=0.000 n=20) Int64N1e18-32 16.165n ± 1% 9.053n ± 1% -44.00% (p=0.000 n=20) Int64N2e18-32 17.945n ± 2% 9.685n ± 2% -46.03% (p=0.000 n=20) Int64N4e18-32 18.35n ± 2% 12.18n ± 1% -33.62% (p=0.000 n=20) Int32N1000-32 3.608n ± 1% 4.862n ± 1% +34.77% (p=0.000 n=20) Int32N1e8-32 3.767n ± 1% 4.758n ± 2% +26.31% (p=0.000 n=20) Int32N1e9-32 4.130n ± 2% 4.772n ± 1% +15.54% (p=0.000 n=20) Int32N2e9-32 4.206n ± 1% 4.847n ± 0% +15.24% (p=0.000 n=20) Float32-32 22.18n ± 4% 22.18n ± 4% ~ (p=0.195 n=20) Float64-32 20.75n ± 4% 21.21n ± 3% ~ (p=0.394 n=20) ExpFloat64-32 12.58n ± 3% 12.39n ± 2% ~ (p=0.032 n=20) NormFloat64-32 7.920n ± 3% 7.422n ± 1% -6.29% (p=0.000 n=20) Perm3-32 40.27n ± 1% 38.00n ± 2% -5.65% (p=0.000 n=20) Perm30-32 213.2n ± 2% 212.7n ± 1% ~ (p=0.995 n=20) Perm30ViaShuffle-32 164.2n ± 2% 187.5n ± 2% +14.22% (p=0.000 n=20) ShuffleOverhead-32 134.7n ± 2% 159.7n ± 1% +18.52% (p=0.000 n=20) Concurrent-32 3.301n ± 2% 3.470n ± 0% +5.10% (p=0.000 n=20) For #61716. Change-Id: Id1481b04202883cd0b23e21bb58d1bca4e482bd3 Reviewed-on: https://go-review.googlesource.com/c/go/+/502500 Reviewed-by: Rob Pike <r@golang.org> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
-rw-r--r--api/next/61716.txt7
-rw-r--r--src/math/rand/v2/example_test.go27
-rw-r--r--src/math/rand/v2/export_test.go4
-rw-r--r--src/math/rand/v2/rand.go212
-rw-r--r--src/math/rand/v2/rand_test.go16
-rw-r--r--src/math/rand/v2/regress_test.go355
6 files changed, 406 insertions, 215 deletions
diff --git a/api/next/61716.txt b/api/next/61716.txt
index 44d40ef1f3..b84e7e1147 100644
--- a/api/next/61716.txt
+++ b/api/next/61716.txt
@@ -7,6 +7,7 @@ pkg math/rand/v2, func Int32N(int32) int32 #61716
pkg math/rand/v2, func Int64() int64 #61716
pkg math/rand/v2, func Int64N(int64) int64 #61716
pkg math/rand/v2, func IntN(int) int #61716
+pkg math/rand/v2, func N[$0 intType]($0) $0 #61716
pkg math/rand/v2, func New(Source) *Rand #61716
pkg math/rand/v2, func NewSource(int64) Source #61716
pkg math/rand/v2, func NewZipf(*Rand, float64, float64, uint64) *Zipf #61716
@@ -14,7 +15,10 @@ pkg math/rand/v2, func NormFloat64() float64 #61716
pkg math/rand/v2, func Perm(int) []int #61716
pkg math/rand/v2, func Shuffle(int, func(int, int)) #61716
pkg math/rand/v2, func Uint32() uint32 #61716
+pkg math/rand/v2, func Uint32N(uint32) uint32 #61716
pkg math/rand/v2, func Uint64() uint64 #61716
+pkg math/rand/v2, func Uint64N(uint64) uint64 #61716
+pkg math/rand/v2, func UintN(uint) uint #61716
pkg math/rand/v2, method (*Rand) ExpFloat64() float64 #61716
pkg math/rand/v2, method (*Rand) Float32() float32 #61716
pkg math/rand/v2, method (*Rand) Float64() float64 #61716
@@ -28,7 +32,10 @@ pkg math/rand/v2, method (*Rand) NormFloat64() float64 #61716
pkg math/rand/v2, method (*Rand) Perm(int) []int #61716
pkg math/rand/v2, method (*Rand) Shuffle(int, func(int, int)) #61716
pkg math/rand/v2, method (*Rand) Uint32() uint32 #61716
+pkg math/rand/v2, method (*Rand) Uint32N(uint32) uint32 #61716
pkg math/rand/v2, method (*Rand) Uint64() uint64 #61716
+pkg math/rand/v2, method (*Rand) Uint64N(uint64) uint64 #61716
+pkg math/rand/v2, method (*Rand) UintN(uint) uint #61716
pkg math/rand/v2, method (*Zipf) Uint64() uint64 #61716
pkg math/rand/v2, type Rand struct #61716
pkg math/rand/v2, type Source interface { Uint64 } #61716
diff --git a/src/math/rand/v2/example_test.go b/src/math/rand/v2/example_test.go
index 4bf4c50a74..7628674439 100644
--- a/src/math/rand/v2/example_test.go
+++ b/src/math/rand/v2/example_test.go
@@ -10,6 +10,7 @@ import (
"os"
"strings"
"text/tabwriter"
+ "time"
)
// These tests serve as an example but also make sure we don't change
@@ -84,15 +85,15 @@ func Example_rand() {
// Output:
// Float32 0.2635776 0.6358173 0.6718283
// Float64 0.628605430454327 0.4504798828572669 0.9562755949377957
- // ExpFloat64 0.3362240648200941 1.4256072328483647 0.24354758816173044
- // NormFloat64 0.17233959114940064 1.577014951434847 0.04259129641113857
- // Int32 1501292890 1486668269 182840835
- // Int64 3546343826724305832 5724354148158589552 5239846799706671610
- // Uint32 2760229429 296659907 1922395059
- // IntN(10) 1 2 5
- // Int32N(10) 4 7 8
- // Int64N(10) 7 6 3
- // Perm [1 4 2 3 0] [4 2 1 3 0] [1 2 4 0 3]
+ // ExpFloat64 0.10400903165715357 0.28855743344575835 0.20489656480442942
+ // NormFloat64 -0.5602299711828513 -0.9211692958208376 -1.4262061075859056
+ // Int32 1817075958 91420417 1486590581
+ // Int64 5724354148158589552 5239846799706671610 5927547564735367388
+ // Uint32 2295813601 961197529 3493134579
+ // IntN(10) 4 5 1
+ // Int32N(10) 8 5 4
+ // Int64N(10) 2 6 3
+ // Perm [3 4 2 1 0] [4 1 2 0 3] [0 2 1 3 4]
}
func ExamplePerm() {
@@ -105,6 +106,14 @@ func ExamplePerm() {
// 0
}
+func ExampleN() {
+ // Print an int64 in the half-open interval [0, 100).
+ fmt.Println(rand.N(int64(100)))
+
+ // Sleep for a random duration between 0 and 100 milliseconds.
+ time.Sleep(rand.N(100 * time.Millisecond))
+}
+
func ExampleShuffle() {
words := strings.Fields("ink runs from the corners of my mouth")
rand.Shuffle(len(words), func(i, j int) {
diff --git a/src/math/rand/v2/export_test.go b/src/math/rand/v2/export_test.go
index f77ba9d4db..16ecb20227 100644
--- a/src/math/rand/v2/export_test.go
+++ b/src/math/rand/v2/export_test.go
@@ -4,10 +4,6 @@
package rand
-func Int32NForTest(r *Rand, n int32) int32 {
- return r.int31n(n)
-}
-
func GetNormalDistributionParameters() (float64, [128]uint32, [128]float32, [128]float32) {
return rn, kn, wn, fn
}
diff --git a/src/math/rand/v2/rand.go b/src/math/rand/v2/rand.go
index 337a6aa5a0..3b8d244154 100644
--- a/src/math/rand/v2/rand.go
+++ b/src/math/rand/v2/rand.go
@@ -18,6 +18,7 @@
package rand
import (
+ "math/bits"
_ "unsafe" // for go:linkname
)
@@ -58,21 +59,16 @@ func New(src Source) *Rand {
func (r *Rand) Int64() int64 { return int64(r.src.Uint64() &^ (1 << 63)) }
// Uint32 returns a pseudo-random 32-bit value as a uint32.
-func (r *Rand) Uint32() uint32 { return uint32(r.Int64() >> 31) }
+func (r *Rand) Uint32() uint32 { return uint32(r.src.Uint64() >> 32) }
// Uint64 returns a pseudo-random 64-bit value as a uint64.
-func (r *Rand) Uint64() uint64 {
- return r.src.Uint64()
-}
+func (r *Rand) Uint64() uint64 { return r.src.Uint64() }
// Int32 returns a non-negative pseudo-random 31-bit integer as an int32.
-func (r *Rand) Int32() int32 { return int32(r.Int64() >> 32) }
+func (r *Rand) Int32() int32 { return int32(r.src.Uint64() >> 33) }
// Int returns a non-negative pseudo-random int.
-func (r *Rand) Int() int {
- u := uint(r.Int64())
- return int(u << 1 >> 1) // clear sign bit if int == int32
-}
+func (r *Rand) Int() int { return int(uint(r.src.Uint64()) << 1 >> 1) }
// Int64N returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
@@ -80,15 +76,105 @@ func (r *Rand) Int64N(n int64) int64 {
if n <= 0 {
panic("invalid argument to Int64N")
}
+ return int64(r.uint64n(uint64(n)))
+}
+
+// Uint64N returns, as a uint64, a non-negative pseudo-random number in the half-open interval [0,n).
+// It panics if n == 0.
+func (r *Rand) Uint64N(n uint64) uint64 {
+ if n == 0 {
+ panic("invalid argument to Uint64N")
+ }
+ return r.uint64n(n)
+}
+
+// uint64n is the no-bounds-checks version of Uint64N.
+func (r *Rand) uint64n(n uint64) uint64 {
+ if is32bit && uint64(uint32(n)) == n {
+ return uint64(r.uint32n(uint32(n)))
+ }
if n&(n-1) == 0 { // n is power of two, can mask
- return r.Int64() & (n - 1)
+ return r.Uint64() & (n - 1)
}
- max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
- v := r.Int64()
- for v > max {
- v = r.Int64()
+
+ // Suppose we have a uint64 x uniform in the range [0,2⁶⁴)
+ // and want to reduce it to the range [0,n) preserving exact uniformity.
+ // We can simulate a scaling arbitrary precision x * (n/2⁶⁴) by
+ // the high bits of a double-width multiply of x*n, meaning (x*n)/2⁶⁴.
+ // Since there are 2⁶⁴ possible inputs x and only n possible outputs,
+ // the output is necessarily biased if n does not divide 2⁶⁴.
+ // In general (x*n)/2⁶⁴ = k for x*n in [k*2⁶⁴,(k+1)*2⁶⁴).
+ // There are either floor(2⁶⁴/n) or ceil(2⁶⁴/n) possible products
+ // in that range, depending on k.
+ // But suppose we reject the sample and try again when
+ // x*n is in [k*2⁶⁴, k*2⁶⁴+(2⁶⁴%n)), meaning rejecting fewer than n possible
+ // outcomes out of the 2⁶⁴.
+ // Now there are exactly floor(2⁶⁴/n) possible ways to produce
+ // each output value k, so we've restored uniformity.
+ // To get valid uint64 math, 2⁶⁴ % n = (2⁶⁴ - n) % n = -n % n,
+ // so the direct implementation of this algorithm would be:
+ //
+ // hi, lo := bits.Mul64(r.Uint64(), n)
+ // thresh := -n % n
+ // for lo < thresh {
+ // hi, lo = bits.Mul64(r.Uint64(), n)
+ // }
+ //
+ // That still leaves an expensive 64-bit division that we would rather avoid.
+ // We know that thresh < n, and n is usually much less than 2⁶⁴, so we can
+ // avoid the last four lines unless lo < n.
+ //
+ // See also:
+ // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction
+ // https://lemire.me/blog/2016/06/30/fast-random-shuffling
+ hi, lo := bits.Mul64(r.Uint64(), n)
+ if lo < n {
+ thresh := -n % n
+ for lo < thresh {
+ hi, lo = bits.Mul64(r.Uint64(), n)
+ }
}
- return v % n
+ return hi
+}
+
+// uint32n is an identical computation to uint64n
+// but optimized for 32-bit systems.
+func (r *Rand) uint32n(n uint32) uint32 {
+ if n&(n-1) == 0 { // n is power of two, can mask
+ return uint32(r.Uint64()) & (n - 1)
+ }
+ // On 64-bit systems we still use the uint64 code below because
+ // the probability of a random uint64 lo being < a uint32 n is near zero,
+ // meaning the unbiasing loop almost never runs.
+ // On 32-bit systems, here we need to implement that same logic in 32-bit math,
+ // both to preserve the exact output sequence observed on 64-bit machines
+ // and to preserve the optimization that the unbiasing loop almost never runs.
+ //
+ // We want to compute
+ // hi, lo := bits.Mul64(r.Uint64(), n)
+ // In terms of 32-bit halves, this is:
+ // x1:x0 := r.Uint64()
+ // 0:hi, lo1:lo0 := bits.Mul64(x1:x0, 0:n)
+ // Writing out the multiplication in terms of bits.Mul32 allows
+ // using direct hardware instructions and avoiding
+ // the computations involving these zeros.
+ x := r.Uint64()
+ lo1a, lo0 := bits.Mul32(uint32(x), n)
+ hi, lo1b := bits.Mul32(uint32(x>>32), n)
+ lo1, c := bits.Add32(lo1a, lo1b, 0)
+ hi += c
+ if lo1 == 0 && lo0 < uint32(n) {
+ n64 := uint64(n)
+ thresh := uint32(-n64 % n64)
+ for lo1 == 0 && lo0 < thresh {
+ x := r.Uint64()
+ lo1a, lo0 = bits.Mul32(uint32(x), n)
+ hi, lo1b = bits.Mul32(uint32(x>>32), n)
+ lo1, c = bits.Add32(lo1a, lo1b, 0)
+ hi += c
+ }
+ }
+ return hi
}
// Int32N returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
@@ -97,51 +183,36 @@ func (r *Rand) Int32N(n int32) int32 {
if n <= 0 {
panic("invalid argument to Int32N")
}
- if n&(n-1) == 0 { // n is power of two, can mask
- return r.Int32() & (n - 1)
- }
- max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
- v := r.Int32()
- for v > max {
- v = r.Int32()
- }
- return v % n
+ return int32(r.uint64n(uint64(n)))
}
-// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
-// n must be > 0, but int31n does not check this; the caller must ensure it.
-// int31n exists because Int32N is inefficient, but Go 1 compatibility
-// requires that the stream of values produced by math/rand/v2 remain unchanged.
-// int31n can thus only be used internally, by newly introduced APIs.
-//
-// For implementation details, see:
-// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction
-// https://lemire.me/blog/2016/06/30/fast-random-shuffling
-func (r *Rand) int31n(n int32) int32 {
- v := r.Uint32()
- prod := uint64(v) * uint64(n)
- low := uint32(prod)
- if low < uint32(n) {
- thresh := uint32(-n) % uint32(n)
- for low < thresh {
- v = r.Uint32()
- prod = uint64(v) * uint64(n)
- low = uint32(prod)
- }
+// Uint32N returns, as a uint32, a non-negative pseudo-random number in the half-open interval [0,n).
+// It panics if n == 0.
+func (r *Rand) Uint32N(n uint32) uint32 {
+ if n == 0 {
+ panic("invalid argument to Uint32N")
}
- return int32(prod >> 32)
+ return uint32(r.uint64n(uint64(n)))
}
+const is32bit = ^uint(0)>>32 == 0
+
// IntN returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) IntN(n int) int {
if n <= 0 {
panic("invalid argument to IntN")
}
- if n <= 1<<31-1 {
- return int(r.Int32N(int32(n)))
+ return int(r.uint64n(uint64(n)))
+}
+
+// UintN returns, as a uint, a non-negative pseudo-random number in the half-open interval [0,n).
+// It panics if n == 0.
+func (r *Rand) UintN(n uint) uint {
+ if n == 0 {
+ panic("invalid argument to UintN")
}
- return int(r.Int64N(int64(n)))
+ return uint(r.uint64n(uint64(n)))
}
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
@@ -214,13 +285,8 @@ func (r *Rand) Shuffle(n int, swap func(i, j int)) {
// there's no way that any PRNG can have a big enough internal state to
// generate even a minuscule percentage of the possible permutations.
// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
- i := n - 1
- for ; i > 1<<31-1-1; i-- {
- j := int(r.Int64N(int64(i + 1)))
- swap(i, j)
- }
- for ; i > 0; i-- {
- j := int(r.int31n(int32(i + 1)))
+ for i := n - 1; i > 0; i-- {
+ j := int(r.uint64n(uint64(i + 1)))
swap(i, j)
}
}
@@ -255,6 +321,16 @@ func Int64() int64 { return globalRand.Int64() }
// from the default Source.
func Uint32() uint32 { return globalRand.Uint32() }
+// Uint64N returns, as a uint64, a pseudo-random number in the half-open interval [0,n)
+// from the default Source.
+// It panics if n <= 0.
+func Uint64N(n uint64) uint64 { return globalRand.Uint64N(n) }
+
+// Uint32N returns, as a uint32, a pseudo-random number in the half-open interval [0,n)
+// from the default Source.
+// It panics if n <= 0.
+func Uint32N(n uint32) uint32 { return globalRand.Uint32N(n) }
+
// Uint64 returns a pseudo-random 64-bit value as a uint64
// from the default Source.
func Uint64() uint64 { return globalRand.Uint64() }
@@ -266,21 +342,41 @@ func Int32() int32 { return globalRand.Int32() }
// Int returns a non-negative pseudo-random int from the default Source.
func Int() int { return globalRand.Int() }
-// Int64N returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n)
+// Int64N returns, as an int64, a pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Int64N(n int64) int64 { return globalRand.Int64N(n) }
-// Int32N returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n)
+// Int32N returns, as an int32, a pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Int32N(n int32) int32 { return globalRand.Int32N(n) }
-// IntN returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n)
+// IntN returns, as an int, a pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func IntN(n int) int { return globalRand.IntN(n) }
+// UintN returns, as a uint, a pseudo-random number in the half-open interval [0,n)
+// from the default Source.
+// It panics if n <= 0.
+func UintN(n uint) uint { return globalRand.UintN(n) }
+
+// N returns a pseudo-random number in the half-open interval [0,n) from the default Source.
+// The type parameter Int can be any integer type.
+// It panics if n <= 0.
+func N[Int intType](n Int) Int {
+ if n <= 0 {
+ panic("invalid argument to N")
+ }
+ return Int(globalRand.uint64n(uint64(n)))
+}
+
+type intType interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0)
// from the default Source.
func Float64() float64 { return globalRand.Float64() }
diff --git a/src/math/rand/v2/rand_test.go b/src/math/rand/v2/rand_test.go
index 6385497575..a9c9e1d5b9 100644
--- a/src/math/rand/v2/rand_test.go
+++ b/src/math/rand/v2/rand_test.go
@@ -418,7 +418,6 @@ func TestUniformFactorial(t *testing.T) {
fn func() int
}{
{name: "Int32N", fn: func() int { return int(r.Int32N(int32(nfact))) }},
- {name: "int31n", fn: func() int { return int(Int32NForTest(r, int32(nfact))) }},
{name: "Perm", fn: func() int { return encodePerm(r.Perm(n)) }},
{name: "Shuffle", fn: func() int {
// Generate permutation using Shuffle.
@@ -437,8 +436,8 @@ func TestUniformFactorial(t *testing.T) {
// See https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test and
// https://www.johndcook.com/Beautiful_Testing_ch10.pdf.
nsamples := 10 * nfact
- if nsamples < 200 {
- nsamples = 200
+ if nsamples < 500 {
+ nsamples = 500
}
samples := make([]float64, nsamples)
for i := range samples {
@@ -497,7 +496,7 @@ func BenchmarkGlobalInt64(b *testing.B) {
Sink = uint64(t)
}
-func BenchmarkGlobalInt63Parallel(b *testing.B) {
+func BenchmarkGlobalInt64Parallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var t int64
for pb.Next() {
@@ -777,3 +776,12 @@ func BenchmarkConcurrent(b *testing.B) {
}
wg.Wait()
}
+
+func TestN(t *testing.T) {
+ for i := 0; i < 1000; i++ {
+ v := N(10)
+ if v < 0 || v >= 10 {
+ t.Fatalf("N(10) returned %d", v)
+ }
+ }
+}
diff --git a/src/math/rand/v2/regress_test.go b/src/math/rand/v2/regress_test.go
index 5c080539e0..beefce8638 100644
--- a/src/math/rand/v2/regress_test.go
+++ b/src/math/rand/v2/regress_test.go
@@ -79,6 +79,18 @@ func TestRegress(t *testing.T) {
}
x = int(big)
+ case reflect.Uint:
+ big := uint64s[repeat%len(uint64s)]
+ if uint64(uint(big)) != big {
+ r.Uint64N(big) // what would happen on 64-bit machine, to keep stream in sync
+ if *update {
+ t.Fatalf("must run -update on 64-bit machine")
+ }
+ p++
+ continue
+ }
+ x = uint(big)
+
case reflect.Int32:
x = int32s[repeat%len(int32s)]
@@ -213,26 +225,26 @@ func replace(t *testing.T, file string, new []byte) {
}
var regressGolden = []any{
- float64(0.5872982159059681), // ExpFloat64()
- float64(0.5372820936538049), // ExpFloat64()
- float64(1.2310533463860203), // ExpFloat64()
- float64(0.6776268958872181), // ExpFloat64()
- float64(0.04451836051028885), // ExpFloat64()
- float64(0.2228940815087735), // ExpFloat64()
- float64(0.09850095778902446), // ExpFloat64()
- float64(0.18902358546064923), // ExpFloat64()
- float64(0.18227281316102673), // ExpFloat64()
- float64(0.31155615099079936), // ExpFloat64()
- float64(0.9474409467969883), // ExpFloat64()
- float64(1.0451058861587306), // ExpFloat64()
- float64(0.21497642445756152), // ExpFloat64()
- float64(1.4215752287217205), // ExpFloat64()
- float64(0.755823964126038), // ExpFloat64()
- float64(0.38996764757787583), // ExpFloat64()
- float64(0.13309377582841803), // ExpFloat64()
- float64(0.2115638815656507), // ExpFloat64()
- float64(0.7176288428497417), // ExpFloat64()
- float64(0.6120456642749681), // ExpFloat64()
+ float64(0.1835616265352068), // ExpFloat64()
+ float64(0.1747899228736829), // ExpFloat64()
+ float64(2.369801563222863), // ExpFloat64()
+ float64(1.8580757676846802), // ExpFloat64()
+ float64(0.35731123690292155), // ExpFloat64()
+ float64(0.5998175837039783), // ExpFloat64()
+ float64(0.466149534807967), // ExpFloat64()
+ float64(1.333748223451787), // ExpFloat64()
+ float64(0.05019983258513916), // ExpFloat64()
+ float64(1.4143832256421573), // ExpFloat64()
+ float64(0.7274094466687158), // ExpFloat64()
+ float64(0.9595398235158843), // ExpFloat64()
+ float64(1.3010086894917756), // ExpFloat64()
+ float64(0.8678483737499929), // ExpFloat64()
+ float64(0.7958895614497015), // ExpFloat64()
+ float64(0.12235329704897674), // ExpFloat64()
+ float64(1.1625413819613253), // ExpFloat64()
+ float64(1.2603945934386542), // ExpFloat64()
+ float64(0.22199446394172706), // ExpFloat64()
+ float64(2.248962105270165), // ExpFloat64()
float32(0.6046603), // Float32()
float32(0.9405091), // Float32()
@@ -297,45 +309,45 @@ var regressGolden = []any{
int64(6263450610539110790), // Int()
int64(2015796113853353331), // Int()
- int32(1298498081), // Int32()
- int32(2019727887), // Int32()
- int32(1427131847), // Int32()
- int32(939984059), // Int32()
- int32(911902081), // Int32()
- int32(1474941318), // Int32()
- int32(140954425), // Int32()
- int32(336122540), // Int32()
- int32(208240456), // Int32()
- int32(646203300), // Int32()
- int32(1106410694), // Int32()
- int32(1747278511), // Int32()
- int32(460128162), // Int32()
- int32(817455089), // Int32()
- int32(683024728), // Int32()
- int32(1006933274), // Int32()
- int32(607811211), // Int32()
- int32(629431445), // Int32()
- int32(1458323237), // Int32()
- int32(469339106), // Int32()
+ int32(649249040), // Int32()
+ int32(1009863943), // Int32()
+ int32(1787307747), // Int32()
+ int32(1543733853), // Int32()
+ int32(455951040), // Int32()
+ int32(737470659), // Int32()
+ int32(1144219036), // Int32()
+ int32(1241803094), // Int32()
+ int32(104120228), // Int32()
+ int32(1396843474), // Int32()
+ int32(553205347), // Int32()
+ int32(873639255), // Int32()
+ int32(1303805905), // Int32()
+ int32(408727544), // Int32()
+ int32(1415254188), // Int32()
+ int32(503466637), // Int32()
+ int32(1377647429), // Int32()
+ int32(1388457546), // Int32()
+ int32(729161618), // Int32()
+ int32(1308411377), // Int32()
int32(0), // Int32N(1)
- int32(7), // Int32N(10)
- int32(7), // Int32N(32)
- int32(459963), // Int32N(1048576)
- int32(688668), // Int32N(1048577)
- int32(474941318), // Int32N(1000000000)
- int32(140954425), // Int32N(1073741824)
- int32(336122540), // Int32N(2147483646)
- int32(208240456), // Int32N(2147483647)
- int32(0), // Int32N(1)
int32(4), // Int32N(10)
- int32(15), // Int32N(32)
- int32(851874), // Int32N(1048576)
- int32(613606), // Int32N(1048577)
- int32(683024728), // Int32N(1000000000)
- int32(1006933274), // Int32N(1073741824)
- int32(607811211), // Int32N(2147483646)
- int32(629431445), // Int32N(2147483647)
+ int32(29), // Int32N(32)
+ int32(883715), // Int32N(1048576)
+ int32(222632), // Int32N(1048577)
+ int32(343411536), // Int32N(1000000000)
+ int32(957743134), // Int32N(1073741824)
+ int32(1241803092), // Int32N(2147483646)
+ int32(104120228), // Int32N(2147483647)
+ int32(0), // Int32N(1)
+ int32(2), // Int32N(10)
+ int32(7), // Int32N(32)
+ int32(96566), // Int32N(1048576)
+ int32(199574), // Int32N(1048577)
+ int32(659029087), // Int32N(1000000000)
+ int32(606492121), // Int32N(1073741824)
+ int32(1377647428), // Int32N(2147483646)
+ int32(1388457546), // Int32N(2147483647)
int32(0), // Int32N(1)
int32(6), // Int32N(10)
@@ -361,109 +373,130 @@ var regressGolden = []any{
int64(2015796113853353331), // Int64()
int64(0), // Int64N(1)
- int64(1), // Int64N(10)
+ int64(4), // Int64N(10)
int64(29), // Int64N(32)
int64(883715), // Int64N(1048576)
- int64(338103), // Int64N(1048577)
- int64(549167320), // Int64N(1000000000)
+ int64(222632), // Int64N(1048577)
+ int64(343411536), // Int64N(1000000000)
int64(957743134), // Int64N(1073741824)
- int64(1927814468), // Int64N(2147483646)
- int64(1375471152), // Int64N(2147483647)
- int64(775422040480279449), // Int64N(1000000000000000000)
+ int64(1241803092), // Int64N(2147483646)
+ int64(104120228), // Int64N(2147483647)
+ int64(650455930292643530), // Int64N(1000000000000000000)
int64(140311732333010180), // Int64N(1152921504606846976)
- int64(7504504064263669287), // Int64N(9223372036854775806)
- int64(1976235410884491574), // Int64N(9223372036854775807)
+ int64(3752252032131834642), // Int64N(9223372036854775806)
+ int64(5599803723869633690), // Int64N(9223372036854775807)
int64(0), // Int64N(1)
- int64(5), // Int64N(10)
+ int64(6), // Int64N(10)
int64(25), // Int64N(32)
int64(920424), // Int64N(1048576)
- int64(345137), // Int64N(1048577)
- int64(539110790), // Int64N(1000000000)
+ int64(677958), // Int64N(1048577)
+ int64(339542337), // Int64N(1000000000)
int64(701992307), // Int64N(1073741824)
int64(0), // IntN(1)
- int64(7), // IntN(10)
- int64(7), // IntN(32)
- int64(459963), // IntN(1048576)
- int64(688668), // IntN(1048577)
- int64(474941318), // IntN(1000000000)
- int64(140954425), // IntN(1073741824)
- int64(336122540), // IntN(2147483646)
- int64(208240456), // IntN(2147483647)
- int64(775422040480279449), // IntN(1000000000000000000)
+ int64(4), // IntN(10)
+ int64(29), // IntN(32)
+ int64(883715), // IntN(1048576)
+ int64(222632), // IntN(1048577)
+ int64(343411536), // IntN(1000000000)
+ int64(957743134), // IntN(1073741824)
+ int64(1241803092), // IntN(2147483646)
+ int64(104120228), // IntN(2147483647)
+ int64(650455930292643530), // IntN(1000000000000000000)
int64(140311732333010180), // IntN(1152921504606846976)
- int64(7504504064263669287), // IntN(9223372036854775806)
- int64(1976235410884491574), // IntN(9223372036854775807)
+ int64(3752252032131834642), // IntN(9223372036854775806)
+ int64(5599803723869633690), // IntN(9223372036854775807)
int64(0), // IntN(1)
- int64(8), // IntN(10)
- int64(26), // IntN(32)
- int64(685707), // IntN(1048576)
- int64(285245), // IntN(1048577)
- int64(458323237), // IntN(1000000000)
- int64(469339106), // IntN(1073741824)
-
- float64(-1.233758177597947), // NormFloat64()
- float64(-0.12634751070237293), // NormFloat64()
- float64(-0.5209945711531503), // NormFloat64()
- float64(2.28571911769958), // NormFloat64()
- float64(0.3228052526115799), // NormFloat64()
- float64(0.5900672875996937), // NormFloat64()
- float64(0.15880774017643562), // NormFloat64()
- float64(0.9892020842955818), // NormFloat64()
- float64(-0.731283016177479), // NormFloat64()
- float64(0.6863807850359727), // NormFloat64()
- float64(1.585403962280623), // NormFloat64()
- float64(0.8382059044208106), // NormFloat64()
- float64(1.2988408475174342), // NormFloat64()
- float64(0.5273583930598617), // NormFloat64()
- float64(0.7324419258045132), // NormFloat64()
- float64(-1.0731798210887524), // NormFloat64()
- float64(0.7001209024399848), // NormFloat64()
- float64(0.4315307186960532), // NormFloat64()
- float64(0.9996261210112625), // NormFloat64()
- float64(-1.5239676725278932), // NormFloat64()
+ int64(6), // IntN(10)
+ int64(25), // IntN(32)
+ int64(920424), // IntN(1048576)
+ int64(677958), // IntN(1048577)
+ int64(339542337), // IntN(1000000000)
+ int64(701992307), // IntN(1073741824)
+
+ float64(0.6694336828657225), // NormFloat64()
+ float64(0.7506128421991493), // NormFloat64()
+ float64(-0.5466367925077582), // NormFloat64()
+ float64(-0.8240444698703802), // NormFloat64()
+ float64(0.11563765115029284), // NormFloat64()
+ float64(-1.3442355710948637), // NormFloat64()
+ float64(-1.0654999977586854), // NormFloat64()
+ float64(0.15938628997241455), // NormFloat64()
+ float64(-0.8046314635002316), // NormFloat64()
+ float64(0.8323920113630076), // NormFloat64()
+ float64(1.0611019472659846), // NormFloat64()
+ float64(-0.8814992544664111), // NormFloat64()
+ float64(0.9236344788106081), // NormFloat64()
+ float64(-1.2854378982224413), // NormFloat64()
+ float64(0.4683572952232405), // NormFloat64()
+ float64(-0.5065217527091702), // NormFloat64()
+ float64(-0.6460803205194869), // NormFloat64()
+ float64(0.7913615856789362), // NormFloat64()
+ float64(-1.6119549224461807), // NormFloat64()
+ float64(0.16216183438701695), // NormFloat64()
[]int{}, // Perm(0)
[]int{0}, // Perm(1)
- []int{0, 3, 2, 4, 1}, // Perm(5)
- []int{3, 7, 0, 1, 6, 2, 4, 5}, // Perm(8)
- []int{2, 3, 7, 6, 1, 8, 0, 5, 4}, // Perm(9)
- []int{5, 2, 6, 4, 3, 7, 8, 9, 1, 0}, // Perm(10)
- []int{0, 11, 2, 5, 14, 7, 3, 1, 13, 8, 9, 4, 10, 6, 12, 15}, // Perm(16)
+ []int{0, 4, 2, 1, 3}, // Perm(5)
+ []int{2, 4, 5, 0, 7, 1, 3, 6}, // Perm(8)
+ []int{6, 4, 1, 5, 7, 3, 0, 8, 2}, // Perm(9)
+ []int{8, 0, 1, 2, 3, 9, 5, 4, 7, 6}, // Perm(10)
+ []int{0, 13, 14, 7, 1, 4, 15, 10, 11, 12, 9, 5, 3, 6, 8, 2}, // Perm(16)
[]int{}, // Perm(0)
[]int{0}, // Perm(1)
- []int{4, 1, 0, 3, 2}, // Perm(5)
- []int{6, 0, 1, 3, 2, 7, 4, 5}, // Perm(8)
- []int{8, 3, 6, 7, 2, 5, 4, 0, 1}, // Perm(9)
- []int{2, 5, 4, 9, 7, 0, 8, 3, 6, 1}, // Perm(10)
- []int{12, 6, 8, 15, 3, 5, 9, 11, 7, 10, 1, 13, 14, 2, 0, 4}, // Perm(16)
+ []int{3, 2, 4, 0, 1}, // Perm(5)
+ []int{7, 1, 6, 4, 2, 3, 5, 0}, // Perm(8)
+ []int{1, 7, 2, 6, 3, 5, 8, 4, 0}, // Perm(9)
+ []int{1, 5, 7, 0, 3, 6, 4, 9, 2, 8}, // Perm(10)
+ []int{6, 13, 2, 11, 14, 7, 10, 12, 4, 5, 3, 0, 15, 9, 1, 8}, // Perm(16)
[]int{}, // Perm(0)
[]int{0}, // Perm(1)
- []int{0, 2, 4, 3, 1}, // Perm(5)
- []int{4, 7, 0, 2, 6, 1, 5, 3}, // Perm(8)
- []int{6, 5, 8, 0, 1, 3, 7, 2, 4}, // Perm(9)
- []int{8, 1, 9, 7, 6, 5, 2, 0, 4, 3}, // Perm(10)
-
- uint32(2596996162), // Uint32()
- uint32(4039455774), // Uint32()
- uint32(2854263694), // Uint32()
- uint32(1879968118), // Uint32()
- uint32(1823804162), // Uint32()
- uint32(2949882636), // Uint32()
- uint32(281908850), // Uint32()
- uint32(672245080), // Uint32()
- uint32(416480912), // Uint32()
- uint32(1292406600), // Uint32()
- uint32(2212821389), // Uint32()
- uint32(3494557023), // Uint32()
- uint32(920256325), // Uint32()
- uint32(1634910179), // Uint32()
- uint32(1366049456), // Uint32()
- uint32(2013866549), // Uint32()
- uint32(1215622422), // Uint32()
- uint32(1258862891), // Uint32()
- uint32(2916646474), // Uint32()
- uint32(938678213), // Uint32()
+ []int{0, 4, 2, 1, 3}, // Perm(5)
+ []int{0, 7, 1, 4, 3, 6, 2, 5}, // Perm(8)
+ []int{1, 3, 0, 4, 5, 2, 8, 7, 6}, // Perm(9)
+ []int{5, 4, 7, 9, 6, 1, 0, 3, 8, 2}, // Perm(10)
+
+ uint32(1298498081), // Uint32()
+ uint32(2019727887), // Uint32()
+ uint32(3574615495), // Uint32()
+ uint32(3087467707), // Uint32()
+ uint32(911902081), // Uint32()
+ uint32(1474941318), // Uint32()
+ uint32(2288438073), // Uint32()
+ uint32(2483606188), // Uint32()
+ uint32(208240456), // Uint32()
+ uint32(2793686948), // Uint32()
+ uint32(1106410694), // Uint32()
+ uint32(1747278511), // Uint32()
+ uint32(2607611810), // Uint32()
+ uint32(817455089), // Uint32()
+ uint32(2830508376), // Uint32()
+ uint32(1006933274), // Uint32()
+ uint32(2755294859), // Uint32()
+ uint32(2776915093), // Uint32()
+ uint32(1458323237), // Uint32()
+ uint32(2616822754), // Uint32()
+
+ uint32(0), // Uint32N(1)
+ uint32(4), // Uint32N(10)
+ uint32(29), // Uint32N(32)
+ uint32(883715), // Uint32N(1048576)
+ uint32(222632), // Uint32N(1048577)
+ uint32(343411536), // Uint32N(1000000000)
+ uint32(957743134), // Uint32N(1073741824)
+ uint32(1241803092), // Uint32N(2147483646)
+ uint32(104120228), // Uint32N(2147483647)
+ uint32(2793686946), // Uint32N(4294967294)
+ uint32(1106410694), // Uint32N(4294967295)
+ uint32(0), // Uint32N(1)
+ uint32(6), // Uint32N(10)
+ uint32(20), // Uint32N(32)
+ uint32(240907), // Uint32N(1048576)
+ uint32(245833), // Uint32N(1048577)
+ uint32(641517075), // Uint32N(1000000000)
+ uint32(340335899), // Uint32N(1073741824)
+ uint32(729161617), // Uint32N(2147483646)
+ uint32(1308411376), // Uint32N(2147483647)
uint64(5577006791947779410), // Uint64()
uint64(8674665223082153551), // Uint64()
@@ -485,4 +518,46 @@ var regressGolden = []any{
uint64(11926759511765359899), // Uint64()
uint64(6263450610539110790), // Uint64()
uint64(11239168150708129139), // Uint64()
+
+ uint64(0), // Uint64N(1)
+ uint64(4), // Uint64N(10)
+ uint64(29), // Uint64N(32)
+ uint64(883715), // Uint64N(1048576)
+ uint64(222632), // Uint64N(1048577)
+ uint64(343411536), // Uint64N(1000000000)
+ uint64(957743134), // Uint64N(1073741824)
+ uint64(1241803092), // Uint64N(2147483646)
+ uint64(104120228), // Uint64N(2147483647)
+ uint64(650455930292643530), // Uint64N(1000000000000000000)
+ uint64(140311732333010180), // Uint64N(1152921504606846976)
+ uint64(3752252032131834642), // Uint64N(9223372036854775806)
+ uint64(5599803723869633690), // Uint64N(9223372036854775807)
+ uint64(3510942875414458835), // Uint64N(18446744073709551614)
+ uint64(12156940908066221322), // Uint64N(18446744073709551615)
+ uint64(0), // Uint64N(1)
+ uint64(6), // Uint64N(10)
+ uint64(27), // Uint64N(32)
+ uint64(205190), // Uint64N(1048576)
+ uint64(638873), // Uint64N(1048577)
+
+ uint64(0), // UintN(1)
+ uint64(4), // UintN(10)
+ uint64(29), // UintN(32)
+ uint64(883715), // UintN(1048576)
+ uint64(222632), // UintN(1048577)
+ uint64(343411536), // UintN(1000000000)
+ uint64(957743134), // UintN(1073741824)
+ uint64(1241803092), // UintN(2147483646)
+ uint64(104120228), // UintN(2147483647)
+ uint64(650455930292643530), // UintN(1000000000000000000)
+ uint64(140311732333010180), // UintN(1152921504606846976)
+ uint64(3752252032131834642), // UintN(9223372036854775806)
+ uint64(5599803723869633690), // UintN(9223372036854775807)
+ uint64(3510942875414458835), // UintN(18446744073709551614)
+ uint64(12156940908066221322), // UintN(18446744073709551615)
+ uint64(0), // UintN(1)
+ uint64(6), // UintN(10)
+ uint64(27), // UintN(32)
+ uint64(205190), // UintN(1048576)
+ uint64(638873), // UintN(1048577)
}