Commit 17dc712c authored by Jeff R. Allen's avatar Jeff R. Allen Committed by Russ Cox

math/rand: Float32/64 must only return values in [0,1)

Float32 and Float64 are now both created by taking the ratio
of two integers which are chosen to fit entirely into the
precision of the desired float type. The previous code
could cast a Float64 with more than 23 bits of ".99999"
into a Float32 of 1.0, which is not in [0,1).

Float32 went from 15 to 21 ns/op (but is now correct).

Fixes #6721.

R=golang-dev, iant, rsc
CC=golang-dev
https://golang.org/cl/22730043
parent 3d2c4df9
......@@ -83,8 +83,8 @@ func Example_rand() {
// Perm generates a random permutation of the numbers [0, n).
show("Perm", r.Perm(5), r.Perm(5), r.Perm(5))
// Output:
// Float32 0.2635776 0.6358173 0.6718283
// Float64 0.628605430454327 0.4504798828572669 0.9562755949377957
// Float32 0.73793465 0.38461488 0.9940225
// Float64 0.6919607852308565 0.29140004584133117 0.2262092163027547
// ExpFloat64 0.3362240648200941 1.4256072328483647 0.24354758816173044
// NormFloat64 0.17233959114940064 1.577014951434847 0.04259129641113857
// Int31 1501292890 1486668269 182840835
......
......@@ -95,10 +95,10 @@ func (r *Rand) Intn(n int) int {
}
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
func (r *Rand) Float64() float64 { return float64(r.Int63n(1<<53)) / (1 << 53) }
// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
func (r *Rand) Float32() float32 { return float32(r.Float64()) }
func (r *Rand) Float32() float32 { return float32(r.Int31n(1<<24)) / (1 << 24) }
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
func (r *Rand) Perm(n int) []int {
......
......@@ -322,6 +322,17 @@ func TestExpTables(t *testing.T) {
}
}
// For issue 6721, the problem came after 7533753 calls, so check 10e6.
func TestFloat32(t *testing.T) {
r := New(NewSource(1))
for ct := 0; ct < 10e6; ct++ {
f := r.Float32()
if f >= 1 {
t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
}
}
}
// Benchmarks
func BenchmarkInt63Threadsafe(b *testing.B) {
......@@ -358,6 +369,13 @@ func BenchmarkInt31n1000(b *testing.B) {
}
}
func BenchmarkFloat32(b *testing.B) {
r := New(NewSource(1))
for n := b.N; n > 0; n-- {
r.Float32()
}
}
func BenchmarkPerm3(b *testing.B) {
r := New(NewSource(1))
for n := b.N; n > 0; n-- {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment