Commit 5aca0514 authored by Russ Cox's avatar Russ Cox

math/rand: restore Go 1.2 value stream for Float32, Float64

CL 22730043 fixed a bug in these functions: they could
return 1.0 despite documentation saying otherwise.
But the fix changed the values returned in the non-buggy case too,
which might invalidate programs depending on a particular
stream when using rand.Seed(0) or when passing their own
Source to rand.New.

The example test says:
        // These tests serve as an example but also make sure we don't change
        // the output of the random number generator when given a fixed seed.
so I think there is some justification for thinking we have
promised not to change the values. In any case, there's no point in
changing the values gratuitously: we can easily fix this bug without
changing the values, and so we should.

That CL just changed the test values too, which defeats the
stated purpose, but it was just a comment.
Add an explicit regression test, which might be
a clearer signal next time that we don't want to change
the values.

Fixes #6721. (again)
Fixes #8013.

LGTM=r
R=iant, r
CC=golang-codereviews
https://golang.org/cl/95460049
parent 7f1d62dc
......@@ -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.73793465 0.38461488 0.9940225
// Float64 0.6919607852308565 0.29140004584133117 0.2262092163027547
// 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
// Int31 1501292890 1486668269 182840835
......
......@@ -101,10 +101,46 @@ 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.Int63n(1<<53)) / (1 << 53) }
func (r *Rand) Float64() float64 {
// A clearer, simpler implementation would be:
// return float64(r.Int63n(1<<53)) / (1<<53)
// However, Go 1 shipped with
// return float64(r.Int63()) / (1 << 63)
// and we want to preserve that value stream.
//
// 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
// will not observe it anyway.
f := float64(r.Int63()) / (1 << 63)
if f == 1 {
f = 0
}
return f
}
// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
func (r *Rand) Float32() float32 { return float32(r.Int31n(1<<24)) / (1 << 24) }
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).
f := float32(r.Float64())
if f == 1 {
f = 0
}
return f
}
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
func (r *Rand) Perm(n int) []int {
......
// Copyright 2014 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.
// Test that random number sequences generated by a specific seed
// do not change from version to version.
//
// Do NOT make changes to the golden outputs. If bugs need to be fixed
// in the underlying code, find ways to fix them that do not affect the
// outputs.
package rand_test
import (
"flag"
"fmt"
. "math/rand"
"reflect"
"testing"
)
var printgolden = flag.Bool("printgolden", false, "print golden results for regression test")
func TestRegress(t *testing.T) {
var int32s = []int32{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1}
var int64s = []int64{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1, 1000000000000000000, 1 << 60, 1<<63 - 2, 1<<63 - 1}
var permSizes = []int{0, 1, 5, 8, 9, 10, 16}
r := New(NewSource(0))
rv := reflect.ValueOf(r)
n := rv.NumMethod()
p := 0
if *printgolden {
fmt.Printf("var regressGolden = []interface{}{\n")
}
for i := 0; i < n; i++ {
m := rv.Type().Method(i)
mv := rv.Method(i)
mt := mv.Type()
if mt.NumOut() == 0 {
continue
}
if mt.NumOut() != 1 {
t.Fatalf("unexpected result count for r.%s", m.Name)
}
r.Seed(0)
for repeat := 0; repeat < 20; repeat++ {
var args []reflect.Value
var argstr string
if mt.NumIn() == 1 {
var x interface{}
switch mt.In(0).Kind() {
default:
t.Fatalf("unexpected argument type for r.%s", m.Name)
case reflect.Int:
if m.Name == "Perm" {
x = permSizes[repeat%len(permSizes)]
break
}
big := int64s[repeat%len(int64s)]
if int64(int(big)) != big {
r.Int63n(big) // what would happen on 64-bit machine, to keep stream in sync
if *printgolden {
fmt.Printf("\tskipped, // must run printgolden on 64-bit machine\n")
}
p++
continue
}
x = int(big)
case reflect.Int32:
x = int32s[repeat%len(int32s)]
case reflect.Int64:
x = int64s[repeat%len(int64s)]
}
argstr = fmt.Sprint(x)
args = append(args, reflect.ValueOf(x))
}
out := mv.Call(args)[0].Interface()
if m.Name == "Int" || m.Name == "Intn" {
out = int64(out.(int))
}
if *printgolden {
var val string
big := int64(1 << 60)
if int64(int(big)) != big && (m.Name == "Int" || m.Name == "Intn") {
// 32-bit machine cannot print 64-bit results
val = "truncated"
} else if reflect.TypeOf(out).Kind() == reflect.Slice {
val = fmt.Sprintf("%#v", out)
} else {
val = fmt.Sprintf("%T(%v)", out, out)
}
fmt.Printf("\t%s, // %s(%s)\n", val, m.Name, argstr)
} else {
want := regressGolden[p]
if m.Name == "Int" {
want = int64(int(uint(want.(int64)) << 1 >> 1))
}
if !reflect.DeepEqual(out, want) {
t.Errorf("r.%s(%s) = %v, want %v", m.Name, argstr, out, want)
}
}
p++
}
}
if *printgolden {
fmt.Printf("}\n")
}
}
var regressGolden = []interface{}{
float64(4.668112973579268), // ExpFloat64()
float64(0.1601593871172866), // ExpFloat64()
float64(3.0465834105636), // ExpFloat64()
float64(0.06385839451671879), // ExpFloat64()
float64(1.8578917487258961), // ExpFloat64()
float64(0.784676123472182), // ExpFloat64()
float64(0.11225477361256932), // ExpFloat64()
float64(0.20173283329802255), // ExpFloat64()
float64(0.3468619496201105), // ExpFloat64()
float64(0.35601103454384536), // ExpFloat64()
float64(0.888376329507869), // ExpFloat64()
float64(1.4081362450365698), // ExpFloat64()
float64(1.0077753823151994), // ExpFloat64()
float64(0.23594100766227588), // ExpFloat64()
float64(2.777245612300007), // ExpFloat64()
float64(0.5202997830662377), // ExpFloat64()
float64(1.2842705247770294), // ExpFloat64()
float64(0.030307408362776206), // ExpFloat64()
float64(2.204156824853721), // ExpFloat64()
float64(2.09891923895058), // ExpFloat64()
float32(0.94519615), // Float32()
float32(0.24496509), // Float32()
float32(0.65595627), // Float32()
float32(0.05434384), // Float32()
float32(0.3675872), // Float32()
float32(0.28948045), // Float32()
float32(0.1924386), // Float32()
float32(0.65533215), // Float32()
float32(0.8971697), // Float32()
float32(0.16735445), // Float32()
float32(0.28858566), // Float32()
float32(0.9026048), // Float32()
float32(0.84978026), // Float32()
float32(0.2730468), // Float32()
float32(0.6090802), // Float32()
float32(0.253656), // Float32()
float32(0.7746542), // Float32()
float32(0.017480763), // Float32()
float32(0.78707397), // Float32()
float32(0.7993937), // Float32()
float64(0.9451961492941164), // Float64()
float64(0.24496508529377975), // Float64()
float64(0.6559562651954052), // Float64()
float64(0.05434383959970039), // Float64()
float64(0.36758720663245853), // Float64()
float64(0.2894804331565928), // Float64()
float64(0.19243860967493215), // Float64()
float64(0.6553321508148324), // Float64()
float64(0.897169713149801), // Float64()
float64(0.16735444255905835), // Float64()
float64(0.2885856518054551), // Float64()
float64(0.9026048462705047), // Float64()
float64(0.8497802817628735), // Float64()
float64(0.2730468047134829), // Float64()
float64(0.6090801919903561), // Float64()
float64(0.25365600644283687), // Float64()
float64(0.7746542391859803), // Float64()
float64(0.017480762156647272), // Float64()
float64(0.7870739563039942), // Float64()
float64(0.7993936979594545), // Float64()
int64(8717895732742165505), // Int()
int64(2259404117704393152), // Int()
int64(6050128673802995827), // Int()
int64(501233450539197794), // Int()
int64(3390393562759376202), // Int()
int64(2669985732393126063), // Int()
int64(1774932891286980153), // Int()
int64(6044372234677422456), // Int()
int64(8274930044578894929), // Int()
int64(1543572285742637646), // Int()
int64(2661732831099943416), // Int()
int64(8325060299420976708), // Int()
int64(7837839688282259259), // Int()
int64(2518412263346885298), // Int()
int64(5617773211005988520), // Int()
int64(2339563716805116249), // Int()
int64(7144924247938981575), // Int()
int64(161231572858529631), // Int()
int64(7259475919510918339), // Int()
int64(7373105480197164748), // Int()
int32(2029793274), // Int31()
int32(526058514), // Int31()
int32(1408655353), // Int31()
int32(116702506), // Int31()
int32(789387515), // Int31()
int32(621654496), // Int31()
int32(413258767), // Int31()
int32(1407315077), // Int31()
int32(1926657288), // Int31()
int32(359390928), // Int31()
int32(619732968), // Int31()
int32(1938329147), // Int31()
int32(1824889259), // Int31()
int32(586363548), // Int31()
int32(1307989752), // Int31()
int32(544722126), // Int31()
int32(1663557311), // Int31()
int32(37539650), // Int31()
int32(1690228450), // Int31()
int32(1716684894), // Int31()
int32(0), // Int31n(1)
int32(4), // Int31n(10)
int32(25), // Int31n(32)
int32(310570), // Int31n(1048576)
int32(857611), // Int31n(1048577)
int32(621654496), // Int31n(1000000000)
int32(413258767), // Int31n(1073741824)
int32(1407315077), // Int31n(2147483646)
int32(1926657288), // Int31n(2147483647)
int32(0), // Int31n(1)
int32(8), // Int31n(10)
int32(27), // Int31n(32)
int32(367019), // Int31n(1048576)
int32(209005), // Int31n(1048577)
int32(307989752), // Int31n(1000000000)
int32(544722126), // Int31n(1073741824)
int32(1663557311), // Int31n(2147483646)
int32(37539650), // Int31n(2147483647)
int32(0), // Int31n(1)
int32(4), // Int31n(10)
int64(8717895732742165505), // Int63()
int64(2259404117704393152), // Int63()
int64(6050128673802995827), // Int63()
int64(501233450539197794), // Int63()
int64(3390393562759376202), // Int63()
int64(2669985732393126063), // Int63()
int64(1774932891286980153), // Int63()
int64(6044372234677422456), // Int63()
int64(8274930044578894929), // Int63()
int64(1543572285742637646), // Int63()
int64(2661732831099943416), // Int63()
int64(8325060299420976708), // Int63()
int64(7837839688282259259), // Int63()
int64(2518412263346885298), // Int63()
int64(5617773211005988520), // Int63()
int64(2339563716805116249), // Int63()
int64(7144924247938981575), // Int63()
int64(161231572858529631), // Int63()
int64(7259475919510918339), // Int63()
int64(7373105480197164748), // Int63()
int64(0), // Int63n(1)
int64(2), // Int63n(10)
int64(19), // Int63n(32)
int64(959842), // Int63n(1048576)
int64(688912), // Int63n(1048577)
int64(393126063), // Int63n(1000000000)
int64(89212473), // Int63n(1073741824)
int64(834026388), // Int63n(2147483646)
int64(1577188963), // Int63n(2147483647)
int64(543572285742637646), // Int63n(1000000000000000000)
int64(355889821886249464), // Int63n(1152921504606846976)
int64(8325060299420976708), // Int63n(9223372036854775806)
int64(7837839688282259259), // Int63n(9223372036854775807)
int64(0), // Int63n(1)
int64(0), // Int63n(10)
int64(25), // Int63n(32)
int64(679623), // Int63n(1048576)
int64(882178), // Int63n(1048577)
int64(510918339), // Int63n(1000000000)
int64(782454476), // Int63n(1073741824)
int64(0), // Intn(1)
int64(4), // Intn(10)
int64(25), // Intn(32)
int64(310570), // Intn(1048576)
int64(857611), // Intn(1048577)
int64(621654496), // Intn(1000000000)
int64(413258767), // Intn(1073741824)
int64(1407315077), // Intn(2147483646)
int64(1926657288), // Intn(2147483647)
int64(543572285742637646), // Intn(1000000000000000000)
int64(355889821886249464), // Intn(1152921504606846976)
int64(8325060299420976708), // Intn(9223372036854775806)
int64(7837839688282259259), // Intn(9223372036854775807)
int64(0), // Intn(1)
int64(2), // Intn(10)
int64(14), // Intn(32)
int64(515775), // Intn(1048576)
int64(839455), // Intn(1048577)
int64(690228450), // Intn(1000000000)
int64(642943070), // Intn(1073741824)
float64(-0.28158587086436215), // NormFloat64()
float64(0.570933095808067), // NormFloat64()
float64(-1.6920196326157044), // NormFloat64()
float64(0.1996229111693099), // NormFloat64()
float64(1.9195199291234621), // NormFloat64()
float64(0.8954838794918353), // NormFloat64()
float64(0.41457072128813166), // NormFloat64()
float64(-0.48700161491544713), // NormFloat64()
float64(-0.1684059662402393), // NormFloat64()
float64(0.37056410998929545), // NormFloat64()
float64(1.0156889027029008), // NormFloat64()
float64(-0.5174422210625114), // NormFloat64()
float64(-0.5565834214413804), // NormFloat64()
float64(0.778320596648391), // NormFloat64()
float64(-1.8970718197702225), // NormFloat64()
float64(0.5229525761688676), // NormFloat64()
float64(-1.5515595563231523), // NormFloat64()
float64(0.0182029289376123), // NormFloat64()
float64(-0.6820951356608795), // NormFloat64()
float64(-0.5987943422687668), // NormFloat64()
[]int{}, // Perm(0)
[]int{0}, // Perm(1)
[]int{0, 4, 1, 3, 2}, // Perm(5)
[]int{3, 1, 0, 4, 7, 5, 2, 6}, // Perm(8)
[]int{5, 0, 3, 6, 7, 4, 2, 1, 8}, // Perm(9)
[]int{4, 5, 0, 2, 6, 9, 3, 1, 8, 7}, // Perm(10)
[]int{14, 2, 0, 8, 3, 5, 13, 12, 1, 4, 6, 7, 11, 9, 15, 10}, // Perm(16)
[]int{}, // Perm(0)
[]int{0}, // Perm(1)
[]int{3, 0, 1, 2, 4}, // Perm(5)
[]int{5, 1, 2, 0, 4, 7, 3, 6}, // Perm(8)
[]int{4, 0, 6, 8, 1, 5, 2, 7, 3}, // Perm(9)
[]int{8, 6, 1, 7, 5, 4, 3, 2, 9, 0}, // Perm(10)
[]int{0, 3, 13, 2, 15, 4, 10, 1, 8, 14, 7, 6, 12, 9, 5, 11}, // Perm(16)
[]int{}, // Perm(0)
[]int{0}, // Perm(1)
[]int{0, 4, 2, 1, 3}, // Perm(5)
[]int{2, 1, 7, 0, 6, 3, 4, 5}, // Perm(8)
[]int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9)
[]int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
uint32(4059586549), // Uint32()
uint32(1052117029), // Uint32()
uint32(2817310706), // Uint32()
uint32(233405013), // Uint32()
uint32(1578775030), // Uint32()
uint32(1243308993), // Uint32()
uint32(826517535), // Uint32()
uint32(2814630155), // Uint32()
uint32(3853314576), // Uint32()
uint32(718781857), // Uint32()
uint32(1239465936), // Uint32()
uint32(3876658295), // Uint32()
uint32(3649778518), // Uint32()
uint32(1172727096), // Uint32()
uint32(2615979505), // Uint32()
uint32(1089444252), // Uint32()
uint32(3327114623), // Uint32()
uint32(75079301), // Uint32()
uint32(3380456901), // Uint32()
uint32(3433369789), // Uint32()
}
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