Source File
rand.go
Belonging Package
math/rand/v2
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package rand implements pseudo-random number generators suitable for tasks
// such as simulation, but it should not be used for security-sensitive work.
//
// Random numbers are generated by a [Source], usually wrapped in a [Rand].
// Both types should be used by a single goroutine at a time: sharing among
// multiple goroutines requires some kind of synchronization.
//
// Top-level functions, such as [Float64] and [Int],
// are safe for concurrent use by multiple goroutines.
//
// This package's outputs might be easily predictable regardless of how it's
// seeded. For random numbers suitable for security-sensitive work, see the
// [crypto/rand] package.
package rand
import (
_ // for go:linkname
)
// A Source is a source of uniformly-distributed
// pseudo-random uint64 values in the range [0, 1<<64).
//
// A Source is not safe for concurrent use by multiple goroutines.
type Source interface {
Uint64() uint64
}
// A Rand is a source of random numbers.
type Rand struct {
src Source
}
// New returns a new Rand that uses random values from src
// to generate other random values.
func ( Source) *Rand {
return &Rand{src: }
}
// Int64 returns a non-negative pseudo-random 63-bit integer as an int64.
func ( *Rand) () int64 { return int64(.src.Uint64() &^ (1 << 63)) }
// Uint32 returns a pseudo-random 32-bit value as a uint32.
func ( *Rand) () uint32 { return uint32(.src.Uint64() >> 32) }
// Uint64 returns a pseudo-random 64-bit value as a uint64.
func ( *Rand) () uint64 { return .src.Uint64() }
// Int32 returns a non-negative pseudo-random 31-bit integer as an int32.
func ( *Rand) () int32 { return int32(.src.Uint64() >> 33) }
// Int returns a non-negative pseudo-random int.
func ( *Rand) () int { return int(uint(.src.Uint64()) << 1 >> 1) }
// Uint returns a pseudo-random uint.
func ( *Rand) () uint { return uint(.src.Uint64()) }
// Int64N returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func ( *Rand) ( int64) int64 {
if <= 0 {
panic("invalid argument to Int64N")
}
return int64(.uint64n(uint64()))
}
// Uint64N returns, as a uint64, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n == 0.
func ( *Rand) ( uint64) uint64 {
if == 0 {
panic("invalid argument to Uint64N")
}
return .uint64n()
}
// uint64n is the no-bounds-checks version of Uint64N.
func ( *Rand) ( uint64) uint64 {
if is32bit && uint64(uint32()) == {
return uint64(.uint32n(uint32()))
}
if &(-1) == 0 { // n is power of two, can mask
return .Uint64() & ( - 1)
}
// 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
, := bits.Mul64(.Uint64(), )
if < {
:= - %
for < {
, = bits.Mul64(.Uint64(), )
}
}
return
}
// uint32n is an identical computation to uint64n
// but optimized for 32-bit systems.
func ( *Rand) ( uint32) uint32 {
if &(-1) == 0 { // n is power of two, can mask
return uint32(.Uint64()) & ( - 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.
:= .Uint64()
, := bits.Mul32(uint32(), )
, := bits.Mul32(uint32(>>32), )
, := bits.Add32(, , 0)
+=
if == 0 && < uint32() {
:= uint64()
:= uint32(- % )
for == 0 && < {
:= .Uint64()
, = bits.Mul32(uint32(), )
, = bits.Mul32(uint32(>>32), )
, = bits.Add32(, , 0)
+=
}
}
return
}
// Int32N returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func ( *Rand) ( int32) int32 {
if <= 0 {
panic("invalid argument to Int32N")
}
return int32(.uint64n(uint64()))
}
// Uint32N returns, as a uint32, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n == 0.
func ( *Rand) ( uint32) uint32 {
if == 0 {
panic("invalid argument to Uint32N")
}
return uint32(.uint64n(uint64()))
}
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 ( *Rand) ( int) int {
if <= 0 {
panic("invalid argument to IntN")
}
return int(.uint64n(uint64()))
}
// UintN returns, as a uint, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n == 0.
func ( *Rand) ( uint) uint {
if == 0 {
panic("invalid argument to UintN")
}
return uint(.uint64n(uint64()))
}
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
func ( *Rand) () float64 {
// There are exactly 1<<53 float64s in [0,1). Use Intn(1<<53) / (1<<53).
return float64(.Uint64()<<11>>11) / (1 << 53)
}
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0).
func ( *Rand) () float32 {
// There are exactly 1<<24 float32s in [0,1). Use Intn(1<<24) / (1<<24).
return float32(.Uint32()<<8>>8) / (1 << 24)
}
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
// in the half-open interval [0,n).
func ( *Rand) ( int) []int {
:= make([]int, )
for := range {
[] =
}
.Shuffle(len(), func(, int) { [], [] = [], [] })
return
}
// Shuffle pseudo-randomizes the order of elements.
// n is the number of elements. Shuffle panics if n < 0.
// swap swaps the elements with indexes i and j.
func ( *Rand) ( int, func(, int)) {
if < 0 {
panic("invalid argument to Shuffle")
}
// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
// Shuffle really ought not be called with n that doesn't fit in 32 bits.
// Not only will it take a very long time, but with 2³¹! possible permutations,
// 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.
for := - 1; > 0; -- {
:= int(.uint64n(uint64( + 1)))
(, )
}
}
/*
* Top-level convenience functions
*/
// globalRand is the source of random numbers for the top-level
// convenience functions.
var globalRand = &Rand{src: runtimeSource{}}
//go:linkname runtime_rand runtime.rand
func runtime_rand() uint64
// runtimeSource is a Source that uses the runtime fastrand functions.
type runtimeSource struct{}
func (runtimeSource) () uint64 {
return runtime_rand()
}
// Int64 returns a non-negative pseudo-random 63-bit integer as an int64
// from the default Source.
func () int64 { return globalRand.Int64() }
// Uint32 returns a pseudo-random 32-bit value as a uint32
// from the default Source.
func () 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 ( uint64) uint64 { return globalRand.Uint64N() }
// 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 ( uint32) uint32 { return globalRand.Uint32N() }
// Uint64 returns a pseudo-random 64-bit value as a uint64
// from the default Source.
func () uint64 { return globalRand.Uint64() }
// Int32 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func () int32 { return globalRand.Int32() }
// Int returns a non-negative pseudo-random int from the default Source.
func () int { return globalRand.Int() }
// Uint returns a pseudo-random uint from the default Source.
func () uint { return globalRand.Uint() }
// 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 ( int64) int64 { return globalRand.Int64N() }
// 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 ( int32) int32 { return globalRand.Int32N() }
// 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 ( int) int { return globalRand.IntN() }
// 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 ( uint) uint { return globalRand.UintN() }
// 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 [ intType]( ) {
if <= 0 {
panic("invalid argument to N")
}
return (globalRand.uint64n(uint64()))
}
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 { return globalRand.Float64() }
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0)
// from the default Source.
func () float32 { return globalRand.Float32() }
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
// in the half-open interval [0,n) from the default Source.
func ( int) []int { return globalRand.Perm() }
// Shuffle pseudo-randomizes the order of elements using the default Source.
// n is the number of elements. Shuffle panics if n < 0.
// swap swaps the elements with indexes i and j.
func ( int, func(, int)) { globalRand.Shuffle(, ) }
// NormFloat64 returns a normally distributed float64 in the range
// [-math.MaxFloat64, +math.MaxFloat64] with
// standard normal distribution (mean = 0, stddev = 1)
// from the default Source.
// To produce a different normal distribution, callers can
// adjust the output using:
//
// sample = NormFloat64() * desiredStdDev + desiredMean
func () float64 { return globalRand.NormFloat64() }
// ExpFloat64 returns an exponentially distributed float64 in the range
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source.
// To produce a distribution with a different rate parameter,
// callers can adjust the output using:
//
// sample = ExpFloat64() / desiredRateParameter
func () float64 { return globalRand.ExpFloat64() }
The pages are generated with Golds v0.7.3. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |