Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is the beginning of the math/rand/v2 package from proposal #61716. Start by copying old API. This CL copies math/rand/* to math/rand/v2 and updates references to math/rand to add v2 throughout. Later CLs will make the v2 changes. For #61716. Change-Id: I1624ccffae3dfa442d4ba2461942decbd076e11b Reviewed-on: https://go-review.googlesource.com/c/go/+/502495 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Rob Pike <r@golang.org>
- Loading branch information
Showing
16 changed files
with
2,885 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
pkg math/rand/v2, func ExpFloat64() float64 #61716 | ||
pkg math/rand/v2, func Float32() float32 #61716 | ||
pkg math/rand/v2, func Float64() float64 #61716 | ||
pkg math/rand/v2, func Int() int #61716 | ||
pkg math/rand/v2, func Int31() int32 #61716 | ||
pkg math/rand/v2, func Int31n(int32) int32 #61716 | ||
pkg math/rand/v2, func Int63() int64 #61716 | ||
pkg math/rand/v2, func Int63n(int64) int64 #61716 | ||
pkg math/rand/v2, func Intn(int) int #61716 | ||
pkg math/rand/v2, func New(Source) *Rand #61716 | ||
pkg math/rand/v2, func NewSource(int64) Source #61716 | ||
pkg math/rand/v2, func NewZipf(*Rand, float64, float64, uint64) *Zipf #61716 | ||
pkg math/rand/v2, func NormFloat64() float64 #61716 | ||
pkg math/rand/v2, func Perm(int) []int #61716 | ||
pkg math/rand/v2, func Read //deprecated #61716 | ||
pkg math/rand/v2, func Read([]uint8) (int, error) #61716 | ||
pkg math/rand/v2, func Seed //deprecated #61716 | ||
pkg math/rand/v2, func Seed(int64) #61716 | ||
pkg math/rand/v2, func Shuffle(int, func(int, int)) #61716 | ||
pkg math/rand/v2, func Uint32() uint32 #61716 | ||
pkg math/rand/v2, func Uint64() uint64 #61716 | ||
pkg math/rand/v2, method (*Rand) ExpFloat64() float64 #61716 | ||
pkg math/rand/v2, method (*Rand) Float32() float32 #61716 | ||
pkg math/rand/v2, method (*Rand) Float64() float64 #61716 | ||
pkg math/rand/v2, method (*Rand) Int() int #61716 | ||
pkg math/rand/v2, method (*Rand) Int31() int32 #61716 | ||
pkg math/rand/v2, method (*Rand) Int31n(int32) int32 #61716 | ||
pkg math/rand/v2, method (*Rand) Int63() int64 #61716 | ||
pkg math/rand/v2, method (*Rand) Int63n(int64) int64 #61716 | ||
pkg math/rand/v2, method (*Rand) Intn(int) int #61716 | ||
pkg math/rand/v2, method (*Rand) NormFloat64() float64 #61716 | ||
pkg math/rand/v2, method (*Rand) Perm(int) []int #61716 | ||
pkg math/rand/v2, method (*Rand) Read([]uint8) (int, error) #61716 | ||
pkg math/rand/v2, method (*Rand) Seed(int64) #61716 | ||
pkg math/rand/v2, method (*Rand) Shuffle(int, func(int, int)) #61716 | ||
pkg math/rand/v2, method (*Rand) Uint32() uint32 #61716 | ||
pkg math/rand/v2, method (*Rand) Uint64() uint64 #61716 | ||
pkg math/rand/v2, method (*Zipf) Uint64() uint64 #61716 | ||
pkg math/rand/v2, type Rand struct #61716 | ||
pkg math/rand/v2, type Source interface { Int63, Seed } #61716 | ||
pkg math/rand/v2, type Source interface, Int63() int64 #61716 | ||
pkg math/rand/v2, type Source interface, Seed(int64) #61716 | ||
pkg math/rand/v2, type Source64 interface { Int63, Seed, Uint64 } #61716 | ||
pkg math/rand/v2, type Source64 interface, Int63() int64 #61716 | ||
pkg math/rand/v2, type Source64 interface, Seed(int64) #61716 | ||
pkg math/rand/v2, type Source64 interface, Uint64() uint64 #61716 | ||
pkg math/rand/v2, type Zipf struct #61716 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Copyright 2022 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_test | ||
|
||
import ( | ||
. "math/rand/v2" | ||
"testing" | ||
) | ||
|
||
// This test is first, in its own file with an alphabetically early name, | ||
// to try to make sure that it runs early. It has the best chance of | ||
// detecting deterministic seeding if it's the first test that runs. | ||
|
||
func TestAuto(t *testing.T) { | ||
// Pull out 10 int64s from the global source | ||
// and then check that they don't appear in that | ||
// order in the deterministic Seed(1) result. | ||
var out []int64 | ||
for i := 0; i < 10; i++ { | ||
out = append(out, Int63()) | ||
} | ||
|
||
// Look for out in Seed(1)'s output. | ||
// Strictly speaking, we should look for them in order, | ||
// but this is good enough and not significantly more | ||
// likely to have a false positive. | ||
Seed(1) | ||
found := 0 | ||
for i := 0; i < 1000; i++ { | ||
x := Int63() | ||
if x == out[found] { | ||
found++ | ||
if found == len(out) { | ||
t.Fatalf("found unseeded output in Seed(1) output") | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// Copyright 2023 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_test | ||
|
||
import ( | ||
"fmt" | ||
"internal/race" | ||
"internal/testenv" | ||
. "math/rand/v2" | ||
"os" | ||
"runtime" | ||
"strconv" | ||
"sync" | ||
"testing" | ||
) | ||
|
||
// Test that racy access to the default functions behaves reasonably. | ||
func TestDefaultRace(t *testing.T) { | ||
// Skip the test in short mode, but even in short mode run | ||
// the test if we are using the race detector, because part | ||
// of this is to see whether the race detector reports any problems. | ||
if testing.Short() && !race.Enabled { | ||
t.Skip("skipping starting another executable in short mode") | ||
} | ||
|
||
const env = "GO_RAND_TEST_HELPER_CODE" | ||
if v := os.Getenv(env); v != "" { | ||
doDefaultTest(t, v) | ||
return | ||
} | ||
|
||
t.Parallel() | ||
|
||
for i := 0; i < 6; i++ { | ||
i := i | ||
t.Run(strconv.Itoa(i), func(t *testing.T) { | ||
t.Parallel() | ||
exe, err := os.Executable() | ||
if err != nil { | ||
exe = os.Args[0] | ||
} | ||
cmd := testenv.Command(t, exe, "-test.run=TestDefaultRace") | ||
cmd = testenv.CleanCmdEnv(cmd) | ||
cmd.Env = append(cmd.Env, fmt.Sprintf("GO_RAND_TEST_HELPER_CODE=%d", i/2)) | ||
if i%2 != 0 { | ||
cmd.Env = append(cmd.Env, "GODEBUG=randautoseed=0") | ||
} | ||
out, err := cmd.CombinedOutput() | ||
if len(out) > 0 { | ||
t.Logf("%s", out) | ||
} | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// doDefaultTest should be run before there have been any calls to the | ||
// top-level math/rand functions. Make sure that we can make concurrent | ||
// calls to top-level functions and to Seed without any duplicate values. | ||
// This will also give the race detector a change to report any problems. | ||
func doDefaultTest(t *testing.T, v string) { | ||
code, err := strconv.Atoi(v) | ||
if err != nil { | ||
t.Fatalf("internal error: unrecognized code %q", v) | ||
} | ||
|
||
goroutines := runtime.GOMAXPROCS(0) | ||
if goroutines < 4 { | ||
goroutines = 4 | ||
} | ||
|
||
ch := make(chan uint64, goroutines*3) | ||
var wg sync.WaitGroup | ||
|
||
// The various tests below should not cause race detector reports | ||
// and should not produce duplicate results. | ||
// | ||
// Note: these tests can theoretically fail when using fastrand64 | ||
// in that it is possible to coincidentally get the same random | ||
// number twice. That could happen something like 1 / 2**64 times, | ||
// which is rare enough that it may never happen. We don't worry | ||
// about that case. | ||
|
||
switch code { | ||
case 0: | ||
// Call Seed and Uint64 concurrently. | ||
wg.Add(goroutines) | ||
for i := 0; i < goroutines; i++ { | ||
go func(s int64) { | ||
defer wg.Done() | ||
Seed(s) | ||
}(int64(i) + 100) | ||
} | ||
wg.Add(goroutines) | ||
for i := 0; i < goroutines; i++ { | ||
go func() { | ||
defer wg.Done() | ||
ch <- Uint64() | ||
}() | ||
} | ||
case 1: | ||
// Call Uint64 concurrently with no Seed. | ||
wg.Add(goroutines) | ||
for i := 0; i < goroutines; i++ { | ||
go func() { | ||
defer wg.Done() | ||
ch <- Uint64() | ||
}() | ||
} | ||
case 2: | ||
// Start with Uint64 to pick the fast source, then call | ||
// Seed and Uint64 concurrently. | ||
ch <- Uint64() | ||
wg.Add(goroutines) | ||
for i := 0; i < goroutines; i++ { | ||
go func(s int64) { | ||
defer wg.Done() | ||
Seed(s) | ||
}(int64(i) + 100) | ||
} | ||
wg.Add(goroutines) | ||
for i := 0; i < goroutines; i++ { | ||
go func() { | ||
defer wg.Done() | ||
ch <- Uint64() | ||
}() | ||
} | ||
default: | ||
t.Fatalf("internal error: unrecognized code %d", code) | ||
} | ||
|
||
go func() { | ||
wg.Wait() | ||
close(ch) | ||
}() | ||
|
||
m := make(map[uint64]bool) | ||
for i := range ch { | ||
if m[i] { | ||
t.Errorf("saw %d twice", i) | ||
} | ||
m[i] = true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// Copyright 2012 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_test | ||
|
||
import ( | ||
"fmt" | ||
"math/rand/v2" | ||
"os" | ||
"strings" | ||
"text/tabwriter" | ||
) | ||
|
||
// 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. | ||
|
||
func Example() { | ||
answers := []string{ | ||
"It is certain", | ||
"It is decidedly so", | ||
"Without a doubt", | ||
"Yes definitely", | ||
"You may rely on it", | ||
"As I see it yes", | ||
"Most likely", | ||
"Outlook good", | ||
"Yes", | ||
"Signs point to yes", | ||
"Reply hazy try again", | ||
"Ask again later", | ||
"Better not tell you now", | ||
"Cannot predict now", | ||
"Concentrate and ask again", | ||
"Don't count on it", | ||
"My reply is no", | ||
"My sources say no", | ||
"Outlook not so good", | ||
"Very doubtful", | ||
} | ||
fmt.Println("Magic 8-Ball says:", answers[rand.Intn(len(answers))]) | ||
} | ||
|
||
// This example shows the use of each of the methods on a *Rand. | ||
// The use of the global functions is the same, without the receiver. | ||
func Example_rand() { | ||
// Create and seed the generator. | ||
// Typically a non-fixed seed should be used, such as time.Now().UnixNano(). | ||
// Using a fixed seed will produce the same output on every run. | ||
r := rand.New(rand.NewSource(99)) | ||
|
||
// The tabwriter here helps us generate aligned output. | ||
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) | ||
defer w.Flush() | ||
show := func(name string, v1, v2, v3 any) { | ||
fmt.Fprintf(w, "%s\t%v\t%v\t%v\n", name, v1, v2, v3) | ||
} | ||
|
||
// Float32 and Float64 values are in [0, 1). | ||
show("Float32", r.Float32(), r.Float32(), r.Float32()) | ||
show("Float64", r.Float64(), r.Float64(), r.Float64()) | ||
|
||
// ExpFloat64 values have an average of 1 but decay exponentially. | ||
show("ExpFloat64", r.ExpFloat64(), r.ExpFloat64(), r.ExpFloat64()) | ||
|
||
// NormFloat64 values have an average of 0 and a standard deviation of 1. | ||
show("NormFloat64", r.NormFloat64(), r.NormFloat64(), r.NormFloat64()) | ||
|
||
// Int31, Int63, and Uint32 generate values of the given width. | ||
// The Int method (not shown) is like either Int31 or Int63 | ||
// depending on the size of 'int'. | ||
show("Int31", r.Int31(), r.Int31(), r.Int31()) | ||
show("Int63", r.Int63(), r.Int63(), r.Int63()) | ||
show("Uint32", r.Uint32(), r.Uint32(), r.Uint32()) | ||
|
||
// Intn, Int31n, and Int63n limit their output to be < n. | ||
// They do so more carefully than using r.Int()%n. | ||
show("Intn(10)", r.Intn(10), r.Intn(10), r.Intn(10)) | ||
show("Int31n(10)", r.Int31n(10), r.Int31n(10), r.Int31n(10)) | ||
show("Int63n(10)", r.Int63n(10), r.Int63n(10), r.Int63n(10)) | ||
|
||
// 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 | ||
// ExpFloat64 0.3362240648200941 1.4256072328483647 0.24354758816173044 | ||
// NormFloat64 0.17233959114940064 1.577014951434847 0.04259129641113857 | ||
// Int31 1501292890 1486668269 182840835 | ||
// Int63 3546343826724305832 5724354148158589552 5239846799706671610 | ||
// Uint32 2760229429 296659907 1922395059 | ||
// Intn(10) 1 2 5 | ||
// Int31n(10) 4 7 8 | ||
// Int63n(10) 7 6 3 | ||
// Perm [1 4 2 3 0] [4 2 1 3 0] [1 2 4 0 3] | ||
} | ||
|
||
func ExamplePerm() { | ||
for _, value := range rand.Perm(3) { | ||
fmt.Println(value) | ||
} | ||
|
||
// Unordered output: 1 | ||
// 2 | ||
// 0 | ||
} | ||
|
||
func ExampleShuffle() { | ||
words := strings.Fields("ink runs from the corners of my mouth") | ||
rand.Shuffle(len(words), func(i, j int) { | ||
words[i], words[j] = words[j], words[i] | ||
}) | ||
fmt.Println(words) | ||
} | ||
|
||
func ExampleShuffle_slicesInUnison() { | ||
numbers := []byte("12345") | ||
letters := []byte("ABCDE") | ||
// Shuffle numbers, swapping corresponding entries in letters at the same time. | ||
rand.Shuffle(len(numbers), func(i, j int) { | ||
numbers[i], numbers[j] = numbers[j], numbers[i] | ||
letters[i], letters[j] = letters[j], letters[i] | ||
}) | ||
for i := range numbers { | ||
fmt.Printf("%c: %c\n", letters[i], numbers[i]) | ||
} | ||
} | ||
|
||
func ExampleIntn() { | ||
fmt.Println(rand.Intn(100)) | ||
fmt.Println(rand.Intn(100)) | ||
fmt.Println(rand.Intn(100)) | ||
} |
Oops, something went wrong.