mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 20:28:17 +08:00
add function B for package grand; improve package grand
This commit is contained in:
parent
bd27258c46
commit
4164059211
@ -8,6 +8,7 @@
|
||||
package grand
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@ -28,6 +29,23 @@ func MeetProb(prob float32) bool {
|
||||
return Intn(1e7) < int(prob*1e7)
|
||||
}
|
||||
|
||||
// B retrieves and returns random bytes of given length <n>.
|
||||
func B(n int) []byte {
|
||||
if n <= 0 {
|
||||
return nil
|
||||
}
|
||||
i := 0
|
||||
b := make([]byte, n)
|
||||
for {
|
||||
copy(b[i:], <-bufferChan)
|
||||
i += 4
|
||||
if i >= n {
|
||||
break
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// N returns a random int between min and max: [min, max].
|
||||
// The <min> and <max> also support negative numbers.
|
||||
func N(min, max int) int {
|
||||
@ -115,3 +133,20 @@ func Perm(n int) []int {
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Intn returns a int number which is between 0 and max: [0, max).
|
||||
//
|
||||
// Note that:
|
||||
// 1. The <max> can only be greater than 0, or else it returns <max> directly;
|
||||
// 2. The result is greater than or equal to 0, but less than <max>;
|
||||
// 3. The result number is 32bit and less than math.MaxUint32.
|
||||
func Intn(max int) int {
|
||||
if max <= 0 {
|
||||
return max
|
||||
}
|
||||
n := int(binary.LittleEndian.Uint32(<-bufferChan)) % max
|
||||
if (max > 0 && n < 0) || (max < 0 && n > 0) {
|
||||
return -n
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
62
util/grand/grand_buffer.go
Normal file
62
util/grand/grand_buffer.go
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package grand
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
const (
|
||||
// Buffer size for uint32 random number.
|
||||
gBUFFER_SIZE = 10000
|
||||
)
|
||||
|
||||
var (
|
||||
// bufferChan is the buffer for random bytes,
|
||||
// every item storing 4 bytes.
|
||||
bufferChan = make(chan []byte, gBUFFER_SIZE)
|
||||
)
|
||||
|
||||
func init() {
|
||||
go asyncProducingRandomBufferBytesLoop()
|
||||
}
|
||||
|
||||
// asyncProducingRandomBufferBytes is a named goroutine, which uses a asynchronous goroutine
|
||||
// to produce the random bytes, and a buffer chan to store the random bytes.
|
||||
// So it has high performance to generate random numbers.
|
||||
func asyncProducingRandomBufferBytesLoop() {
|
||||
var (
|
||||
step = 0
|
||||
buffer = make([]byte, 1024)
|
||||
)
|
||||
for {
|
||||
if n, err := rand.Read(buffer); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
for i := 0; i < n-4; {
|
||||
bufferChan <- buffer[i : i+4]
|
||||
i++
|
||||
}
|
||||
// Reuse the rand buffer.
|
||||
for i := 0; i < n; i++ {
|
||||
step = int(buffer[0]) % 10
|
||||
if step != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
// The step cannot be 0,
|
||||
// as it will produce the same random number as previous.
|
||||
if step == 0 {
|
||||
step = 2
|
||||
}
|
||||
for i := 0; i < n-4; {
|
||||
bufferChan <- buffer[i : i+4]
|
||||
i += step
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package grand
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
// Buffer size for uint32 random number.
|
||||
gBUFFER_SIZE = 10000
|
||||
)
|
||||
|
||||
var (
|
||||
// Buffer chan.
|
||||
bufferChan = make(chan uint32, gBUFFER_SIZE)
|
||||
)
|
||||
|
||||
// It uses a asynchronous goroutine to produce the random number,
|
||||
// and a buffer chan to store the random numbers.
|
||||
// So it has high performance to generate random numbers.
|
||||
func init() {
|
||||
var (
|
||||
step = 0
|
||||
buffer = make([]byte, 1024)
|
||||
)
|
||||
go func() {
|
||||
for {
|
||||
if n, err := rand.Read(buffer); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
for i := 0; i < n-4; {
|
||||
bufferChan <- binary.LittleEndian.Uint32(buffer[i : i+4])
|
||||
i++
|
||||
}
|
||||
// Reuse the rand buffer.
|
||||
for i := 0; i < n; i++ {
|
||||
step = int(buffer[0]) % 10
|
||||
if step != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
// The step cannot be 0,
|
||||
// as it will produce the same random number as previous.
|
||||
if step == 0 {
|
||||
step = 2
|
||||
}
|
||||
for i := 0; i < n-4; {
|
||||
bufferChan <- binary.BigEndian.Uint32(buffer[i : i+4])
|
||||
i += step
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Intn returns a int number which is between 0 and max: [0, max).
|
||||
//
|
||||
// Note that:
|
||||
// 1. The <max> can only be greater than 0, or else it returns <max> directly;
|
||||
// 2. The result is greater than or equal to 0, but less than <max>;
|
||||
// 3. The result number is 32bit and less than math.MaxUint32.
|
||||
func Intn(max int) int {
|
||||
if max <= 0 {
|
||||
return max
|
||||
}
|
||||
n := int(<-bufferChan) % max
|
||||
if (max > 0 && n < 0) || (max < 0 && n > 0) {
|
||||
return -n
|
||||
}
|
||||
return n
|
||||
}
|
@ -60,6 +60,12 @@ func Benchmark_StrSymbols(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint32Converting(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
binary.LittleEndian.Uint32([]byte{1, 1, 1, 1})
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Buffer(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := rand.Read(buffer); err == nil {
|
||||
|
@ -90,15 +90,7 @@ func Test_Rand(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Str(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
t.Assert(len(grand.S(5)), 5)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_RandS(t *testing.T) {
|
||||
func Test_S(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
t.Assert(len(grand.S(5)), 5)
|
||||
@ -111,6 +103,24 @@ func Test_RandS(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_B(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
b := grand.B(5)
|
||||
t.Assert(len(b), 5)
|
||||
t.AssertNE(b, make([]byte, 5))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Str(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
t.Assert(len(grand.S(5)), 5)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_RandStr(t *testing.T) {
|
||||
str := "我爱GoFrame"
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user