]> Cypherpunks repositories - gostls13.git/commitdiff
math/rand: make Rand fulfill the Reader interface
authorSpencer Nelson <s@spenczar.com>
Fri, 11 Sep 2015 17:41:45 +0000 (13:41 -0400)
committerRob Pike <r@golang.org>
Wed, 16 Sep 2015 17:54:01 +0000 (17:54 +0000)
Add a Read function to Rand which reads random bytes into a buffer.

Fixes #8330

Change-Id: I85b90277b8be9287c6697def8dbefe0029b6ee06
Reviewed-on: https://go-review.googlesource.com/14522
Reviewed-by: Rob Pike <r@golang.org>
src/math/rand/rand.go
src/math/rand/rand_test.go
src/math/rand/regress_test.go

index 6360128e3916ad9195b0064961b6cfd384bb86ef..075b0e580e9a5f27c15e065810c2c5ecc925783a 100644 (file)
@@ -156,6 +156,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 +222,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)
index c61494f8eb8586cd9e517b4191cead5e704db7ba..6a1df4dcb8d9a6992bda80a86677a503262a5ce4 100644 (file)
@@ -342,6 +342,59 @@ func TestFloat32(t *testing.T) {
        }
 }
 
+func testReadUniformity(t *testing.T, n int, seed int64) {
+       r := New(NewSource(seed))
+       buf := make([]byte, n)
+       nRead, err := r.Read(buf)
+       if err != nil {
+               t.Errorf("Read err %v", err)
+       }
+       if nRead != n {
+               t.Errorf("Read returned unexpected n; %d != %d", nRead, n)
+       }
+
+       // Expect a uniform distribution of byte values, which lie in [0, 255].
+       var (
+               mean       = 255.0 / 2
+               stddev     = math.Sqrt(255.0 * 255.0 / 12.0)
+               errorScale = stddev / math.Sqrt(float64(n))
+       )
+
+       expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale}
+
+       // Cast bytes as floats to use the common distribution-validity checks.
+       samples := make([]float64, n)
+       for i, val := range buf {
+               samples[i] = float64(val)
+       }
+       // Make sure that the entire set matches the expected distribution.
+       checkSampleDistribution(t, samples, expected)
+}
+
+func TestRead(t *testing.T) {
+       testBufferSizes := []int{
+               2, 4, 7, 64, 1024, 1 << 16, 1 << 20,
+       }
+       for _, seed := range testSeeds {
+               for _, n := range testBufferSizes {
+                       testReadUniformity(t, n, seed)
+               }
+       }
+}
+
+func TestReadEmpty(t *testing.T) {
+       r := New(NewSource(1))
+       buf := make([]byte, 0)
+       n, err := r.Read(buf)
+       if err != nil {
+               t.Errorf("Read err into empty buffer; %v", err)
+       }
+       if n != 0 {
+               t.Errorf("Read into empty buffer returned unexpected n of %d", n)
+       }
+
+}
+
 // Benchmarks
 
 func BenchmarkInt63Threadsafe(b *testing.B) {
@@ -405,3 +458,30 @@ func BenchmarkPerm30(b *testing.B) {
                r.Perm(30)
        }
 }
+
+func BenchmarkRead3(b *testing.B) {
+       r := New(NewSource(1))
+       buf := make([]byte, 3)
+       b.ResetTimer()
+       for n := b.N; n > 0; n-- {
+               r.Read(buf)
+       }
+}
+
+func BenchmarkRead64(b *testing.B) {
+       r := New(NewSource(1))
+       buf := make([]byte, 64)
+       b.ResetTimer()
+       for n := b.N; n > 0; n-- {
+               r.Read(buf)
+       }
+}
+
+func BenchmarkRead1000(b *testing.B) {
+       r := New(NewSource(1))
+       buf := make([]byte, 1000)
+       b.ResetTimer()
+       for n := b.N; n > 0; n-- {
+               r.Read(buf)
+       }
+}
index 2b012af893c7f1184088e9001e1591f5097e9fcf..9ae53574478a34f651a73d5f23bedb94669ac995 100644 (file)
@@ -25,6 +25,7 @@ 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}
+       var readBufferSizes = []int{1, 7, 8, 9, 10}
        r := New(NewSource(0))
 
        rv := reflect.ValueOf(r)
@@ -40,9 +41,6 @@ func TestRegress(t *testing.T) {
                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
@@ -74,14 +72,25 @@ func TestRegress(t *testing.T) {
 
                                case reflect.Int64:
                                        x = int64s[repeat%len(int64s)]
+
+                               case reflect.Slice:
+                                       if m.Name == "Read" {
+                                               n := readBufferSizes[repeat%len(readBufferSizes)]
+                                               x = make([]byte, n)
+                                       }
                                }
                                argstr = fmt.Sprint(x)
                                args = append(args, reflect.ValueOf(x))
                        }
-                       out := mv.Call(args)[0].Interface()
+
+                       var out interface{}
+                       out = mv.Call(args)[0].Interface()
                        if m.Name == "Int" || m.Name == "Intn" {
                                out = int64(out.(int))
                        }
+                       if m.Name == "Read" {
+                               out = args[0].Interface().([]byte)
+                       }
                        if *printgolden {
                                var val string
                                big := int64(1 << 60)
@@ -332,24 +341,44 @@ var regressGolden = []interface{}{
        []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()
+       []byte{0x1},                         // Read([0])
+       []byte{0xc0, 0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b},                   // Read([0 0 0 0 0 0 0])
+       []byte{0x73, 0xc8, 0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62},            // Read([0 0 0 0 0 0 0 0])
+       []byte{0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd, 0xaf, 0x48},        // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0x39, 0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89, 0x2e}, // Read([0 0 0 0 0 0 0 0 0 0])
+       []byte{0x51}, // Read([0])
+       []byte{0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b},                   // Read([0 0 0 0 0 0 0])
+       []byte{0xf8, 0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44},             // Read([0 0 0 0 0 0 0 0])
+       []byte{0x3b, 0xbf, 0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52},       // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6, 0x59, 0xc1, 0x8f}, // Read([0 0 0 0 0 0 0 0 0 0])
+       []byte{0xc7}, // Read([0])
+       []byte{0x5f, 0x67, 0xcf, 0xe2, 0x42, 0xcf, 0x3c},                   // Read([0 0 0 0 0 0 0])
+       []byte{0xc3, 0x54, 0xf3, 0xed, 0xe2, 0xd6, 0xbe, 0xcc},             // Read([0 0 0 0 0 0 0 0])
+       []byte{0x6a, 0x9f, 0x4a, 0x57, 0x8b, 0xcb, 0x9e, 0xf2, 0xd4},       // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0x6d, 0x29, 0x97, 0x61, 0xea, 0x9e, 0x4f, 0x5a, 0xa6, 0xae}, // Read([0 0 0 0 0 0 0 0 0 0])
+       []byte{0xaa}, // Read([0])
+       []byte{0x20, 0xef, 0xcd, 0x6c, 0xea, 0x84, 0xb6},                   // Read([0 0 0 0 0 0 0])
+       []byte{0x92, 0x5e, 0x60, 0x7b, 0xe0, 0x63, 0x71, 0x6f},             // Read([0 0 0 0 0 0 0 0])
+       []byte{0x4, 0x5c, 0x3f, 0x0, 0xf, 0x8a, 0x79, 0x6b, 0xce},          // Read([0 0 0 0 0 0 0 0 0])
+       []byte{0xaa, 0xca, 0xee, 0xdf, 0xad, 0x5b, 0x50, 0x66, 0x64, 0xe8}, // Read([0 0 0 0 0 0 0 0 0 0])
+       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()
 }