Permalink
Browse files

math/rand: add Rand.Uint64

This adds Uint64 methods to Rand and rngSource.
Rand.Uint64 uses Source.Uint64 directly if it is present.

rngSource.Uint64 provides access to all 64 bits generated by the
underlying ALFG. To ensure high seed quality a 64th bit has been added
to all elements of the array of "cooked" random numbers that are used
for seeding. gen_cooked.go generates both the 63 bit and 64 bit array.

Fixes #4254

Change-Id: I22855618ac69abae3d2799b3e7e59996d4c5a4b1
Reviewed-on: https://go-review.googlesource.com/27253
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information...
FlorianUekermann authored and bradfitz committed Aug 17, 2016
1 parent 9984195 commit 003a598bf28ae8f77919c3bda2abb9d6d4f449bb
Showing with 204 additions and 149 deletions.
  1. +1 −0 src/math/rand/race_test.go
  2. +34 −3 src/math/rand/rand.go
  3. +20 −0 src/math/rand/regress_test.go
  4. +149 −146 src/math/rand/rng.go
@@ -33,6 +33,7 @@ func TestConcurrent(t *testing.T) {
seed += int64(Int63n(Int63()))
seed += int64(NormFloat64())
seed += int64(Uint32())
seed += int64(Uint64())
for _, p := range Perm(10) {
seed += int64(p)
}
@@ -23,6 +23,14 @@ type Source interface {
Seed(seed int64)
}

// A source64 represents a Source, which is also a source
// of uniformly-distributed pseudo-random uint64 values in
// the range [0, 1<<64).
type source64 interface {
Source
Uint64() uint64
}

// NewSource returns a new pseudo-random Source seeded with the given value.
// Unlike the default Source used by top-level functions, this source is not
// safe for concurrent use by multiple goroutines.
@@ -35,6 +43,7 @@ func NewSource(seed int64) Source {
// A Rand is a source of random numbers.
type Rand struct {
src Source
s64 source64 // non-nil if src is source64

// readVal contains remainder of 63-bit integer used for bytes
// generation during most recent Read call.
@@ -48,7 +57,10 @@ type Rand struct {

// New returns a new Rand that uses random values from src
// to generate other random values.
func New(src Source) *Rand { return &Rand{src: src} }
func New(src Source) *Rand {
s64, _ := src.(source64)
return &Rand{src: src, s64: s64}
}

// Seed uses the provided seed value to initialize the generator to a deterministic state.
// Seed should not be called concurrently with any other Rand method.
@@ -68,6 +80,14 @@ func (r *Rand) Int63() int64 { return r.src.Int63() }
// Uint32 returns a pseudo-random 32-bit value as a uint32.
func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }

// Uint64 returns a pseudo-random 64-bit value as a uint64.
func (r *Rand) Uint64() uint64 {
if r.s64 != nil {
return r.s64.Uint64()
}
return uint64(r.Int63())>>31 | uint64(r.Int63())<<32
}

// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }

@@ -209,7 +229,7 @@ func read(p []byte, int63 func() int64, readVal *int64, readPos *int8) (n int, e
* Top-level convenience functions
*/

var globalRand = New(&lockedSource{src: NewSource(1)})
var globalRand = New(&lockedSource{src: NewSource(1).(source64)})

// Seed uses the provided seed value to initialize the default Source to a
// deterministic state. If Seed is not called, the generator behaves as
@@ -226,6 +246,10 @@ func Int63() int64 { return globalRand.Int63() }
// from the default Source.
func Uint32() uint32 { return globalRand.Uint32() }

// Uint64 returns a pseudo-random 64-bit value as a uint64
// from the default Source.
func Uint64() uint64 { return globalRand.Uint64() }

// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func Int31() int32 { return globalRand.Int31() }
@@ -288,7 +312,7 @@ func ExpFloat64() float64 { return globalRand.ExpFloat64() }

type lockedSource struct {
lk sync.Mutex
src Source
src source64
}

func (r *lockedSource) Int63() (n int64) {
@@ -298,6 +322,13 @@ func (r *lockedSource) Int63() (n int64) {
return
}

func (r *lockedSource) Uint64() (n uint64) {
r.lk.Lock()
n = r.src.Uint64()
r.lk.Unlock()
return
}

func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
@@ -381,4 +381,24 @@ var regressGolden = []interface{}{
uint32(75079301), // Uint32()
uint32(3380456901), // Uint32()
uint32(3433369789), // Uint32()
uint64(8717895732742165505), // Uint64()
uint64(2259404117704393152), // Uint64()
uint64(6050128673802995827), // Uint64()
uint64(9724605487393973602), // Uint64()
uint64(12613765599614152010), // Uint64()
uint64(11893357769247901871), // Uint64()
uint64(1774932891286980153), // Uint64()
uint64(15267744271532198264), // Uint64()
uint64(17498302081433670737), // Uint64()
uint64(1543572285742637646), // Uint64()
uint64(11885104867954719224), // Uint64()
uint64(17548432336275752516), // Uint64()
uint64(7837839688282259259), // Uint64()
uint64(2518412263346885298), // Uint64()
uint64(5617773211005988520), // Uint64()
uint64(11562935753659892057), // Uint64()
uint64(16368296284793757383), // Uint64()
uint64(161231572858529631), // Uint64()
uint64(16482847956365694147), // Uint64()
uint64(16596477517051940556), // Uint64()
}
Oops, something went wrong.

0 comments on commit 003a598

Please sign in to comment.