aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/math/rand/rand.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/math/rand/rand.go')
-rw-r--r--libgo/go/math/rand/rand.go47
1 files changed, 33 insertions, 14 deletions
diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go
index 6360128e391..d693bfb52f2 100644
--- a/libgo/go/math/rand/rand.go
+++ b/libgo/go/math/rand/rand.go
@@ -113,19 +113,18 @@ func (r *Rand) Float64() float64 {
//
// There is one bug in the value stream: r.Int63() may be so close
// to 1<<63 that the division rounds up to 1.0, and we've guaranteed
- // that the result is always less than 1.0. To fix that, we treat the
- // range as cyclic and map 1 back to 0. This is justified by observing
- // that while some of the values rounded down to 0, nothing was
- // rounding up to 0, so 0 was underrepresented in the results.
- // Mapping 1 back to zero restores some balance.
- // (The balance is not perfect because the implementation
- // returns denormalized numbers for very small r.Int63(),
- // and those steal from what would normally be 0 results.)
- // The remapping only happens 1/2⁵³ of the time, so most clients
+ // that the result is always less than 1.0.
+ //
+ // We tried to fix this by mapping 1.0 back to 0.0, but since float64
+ // values near 0 are much denser than near 1, mapping 1 to 0 caused
+ // a theoretically significant overshoot in the probability of returning 0.
+ // Instead of that, if we round up to 1, just try again.
+ // Getting 1 only happens 1/2⁵³ of the time, so most clients
// will not observe it anyway.
+again:
f := float64(r.Int63()) / (1 << 63)
if f == 1 {
- f = 0
+ goto again // resample; this branch is taken O(never)
}
return f
}
@@ -134,13 +133,11 @@ func (r *Rand) Float64() float64 {
func (r *Rand) Float32() float32 {
// Same rationale as in Float64: we want to preserve the Go 1 value
// stream except we want to fix it not to return 1.0
- // There is a double rounding going on here, but the argument for
- // mapping 1 to 0 still applies: 0 was underrepresented before,
- // so mapping 1 to 0 doesn't cause too many 0s.
// This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64).
+again:
f := float32(r.Float64())
if f == 1 {
- f = 0
+ goto again // resample; this branch is taken O(very rarely)
}
return f
}
@@ -148,6 +145,11 @@ func (r *Rand) Float32() float32 {
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
func (r *Rand) Perm(n int) []int {
m := make([]int, n)
+ // In the following loop, the iteration when i=0 always swaps m[0] with m[0].
+ // A change to remove this useless iteration is to assign 1 to i in the init
+ // statement. But Perm also effects r. Making this change will affect
+ // the final state of r. So this change can't be made for compatibility
+ // reasons for Go 1.
for i := 0; i < n; i++ {
j := r.Intn(i + 1)
m[i] = m[j]
@@ -156,6 +158,19 @@ func (r *Rand) Perm(n int) []int {
return m
}
+// Read generates len(p) random bytes and writes them into p. It
+// always returns len(p) and a nil error.
+func (r *Rand) Read(p []byte) (n int, err error) {
+ for i := 0; i < len(p); i += 7 {
+ val := r.src.Int63()
+ for j := 0; i+j < len(p) && j < 7; j++ {
+ p[i+j] = byte(val)
+ val >>= 8
+ }
+ }
+ return len(p), nil
+}
+
/*
* Top-level convenience functions
*/
@@ -209,6 +224,10 @@ func Float32() float32 { return globalRand.Float32() }
// from the default Source.
func Perm(n int) []int { return globalRand.Perm(n) }
+// Read generates len(p) random bytes from the default Source and
+// writes them into p. It always returns len(p) and a nil error.
+func Read(p []byte) (n int, err error) { return globalRand.Read(p) }
+
// NormFloat64 returns a normally distributed float64 in the range
// [-math.MaxFloat64, +math.MaxFloat64] with
// standard normal distribution (mean = 0, stddev = 1)