feat: Randomizer

This commit is contained in:
Bobo
2025-04-08 20:31:32 +08:00
parent 3153ff149f
commit 2ab920982a
3 changed files with 270 additions and 5 deletions

View File

@@ -1,16 +1,16 @@
package rand
import (
"math/rand"
"time"
"github.com/tx7do/go-utils/math"
"math/rand"
)
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
var rnd = rand.New(rand.NewSource(Seed(UnixNanoSeed)))
func init() {
rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
if rnd != nil {
rnd = rand.New(rand.NewSource(Seed(UnixNanoSeed)))
}
}
func Float32() float32 {

179
rand/randomizer.go Normal file
View File

@@ -0,0 +1,179 @@
package rand
import (
"github.com/tx7do/go-utils/math"
"math/rand"
)
type Randomizer struct {
rnd *rand.Rand
}
func NewRandomizer(seedType SeedType) *Randomizer {
return &Randomizer{
rnd: rand.New(rand.NewSource(Seed(seedType))),
}
}
func (r *Randomizer) Float32() float32 {
return r.rnd.Float32()
}
func (r *Randomizer) Float64() float64 {
return r.rnd.Float64()
}
func (r *Randomizer) Int() int {
return r.rnd.Int()
}
func (r *Randomizer) Int31() int32 {
return r.rnd.Int31()
}
func (r *Randomizer) Int63() int64 {
return r.rnd.Int63()
}
func (r *Randomizer) Uint32() uint32 {
return r.rnd.Uint32()
}
func (r *Randomizer) Uint64() uint64 {
return r.rnd.Uint64()
}
func (r *Randomizer) Intn(n int) int {
return r.rnd.Intn(n)
}
func (r *Randomizer) Int31n(n int32) int32 {
return r.rnd.Int31n(n)
}
func (r *Randomizer) Int63n(n int64) int64 {
return r.rnd.Int63n(n)
}
// RangeInt 根据区间产生随机数
func (r *Randomizer) RangeInt(min, max int) int {
if min >= max {
return max
}
return min + r.Intn(max-min+1)
}
// RangeInt32 根据区间产生随机数
func (r *Randomizer) RangeInt32(min, max int32) int32 {
if min >= max {
return max
}
return min + r.Int31n(max-min+1)
}
// RangeInt64 根据区间产生随机数
func (r *Randomizer) RangeInt64(min, max int64) int64 {
if min >= max {
return max
}
return min + r.Int63n(max-min+1)
}
// RangeUint 根据区间产生随机数
func (r *Randomizer) RangeUint(min, max uint) uint {
if min >= max {
return max
}
return min + uint(r.Intn(int(max-min+1)))
}
// RangeUint32 根据区间产生随机数
func (r *Randomizer) RangeUint32(min, max uint32) uint32 {
if min >= max {
return max
}
return min + uint32(r.Int31n(int32(max-min+1)))
}
// RangeUint64 根据区间产生随机数
func (r *Randomizer) RangeUint64(min, max uint64) uint64 {
if min >= max {
return max
}
return min + uint64(r.Int63n(int64(max-min+1)))
}
// RangeFloat32 根据区间产生随机数
func (r *Randomizer) RangeFloat32(min, max float32) float32 {
if min >= max {
return max
}
return min + r.Float32()*(max-min)
}
// RangeFloat64 根据区间产生随机数
func (r *Randomizer) RangeFloat64(min, max float64) float64 {
if min >= max {
return max
}
return min + r.Float64()*(max-min)
}
// RandomString 随机字符串,包含大小写字母和数字
func (r *Randomizer) RandomString(l int) string {
bytes := make([]byte, l)
for i := 0; i < l; i++ {
x := r.Intn(3)
switch x {
case 0:
bytes[i] = byte(r.RangeInt(65, 90)) //大写字母
case 1:
bytes[i] = byte(r.RangeInt(97, 122))
case 2:
bytes[i] = byte(r.Intn(10))
}
}
return string(bytes)
}
// WeightedChoice 根据权重随机返回对应选项的索引O(n)
func (r *Randomizer) WeightedChoice(weightArray []int) int {
if weightArray == nil {
return -1
}
total := math.SumInt(weightArray)
rv := r.Int63n(total)
for i, v := range weightArray {
if rv < int64(v) {
return i
}
rv -= int64(v)
}
return len(weightArray) - 1
}
// NonWeightedChoice 根据权重随机返回对应选项的索引O(n). 权重大于等于0
func (r *Randomizer) NonWeightedChoice(weightArray []int) int {
if weightArray == nil {
return -1
}
for i, weight := range weightArray {
if weight < 0 {
weightArray[i] = 0
}
}
total := math.SumInt(weightArray)
rv := r.Int63n(total)
for i, v := range weightArray {
if rv < int64(v) {
return i
}
rv -= int64(v)
}
return len(weightArray) - 1
}

86
rand/randomizer_test.go Normal file
View File

@@ -0,0 +1,86 @@
package rand
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestRandomizer_RangeUint32_MinEqualsMax(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.RangeUint32(5, 5)
assert.Equal(t, uint32(5), result)
}
func TestRandomizer_RangeUint32_MinGreaterThanMax(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.RangeUint32(10, 5)
assert.Equal(t, uint32(5), result)
}
func TestRandomizer_RangeUint32_PositiveRange(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
for i := 0; i < 1000; i++ {
result := r.RangeUint32(1, 10)
assert.True(t, result >= 1)
assert.True(t, result <= 10)
}
}
func TestRandomizer_RangeUint64_MinEqualsMax(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.RangeUint64(5, 5)
assert.Equal(t, uint64(5), result)
}
func TestRandomizer_RangeUint64_MinGreaterThanMax(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.RangeUint64(10, 5)
assert.Equal(t, uint64(5), result)
}
func TestRandomizer_RangeUint64_PositiveRange(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
for i := 0; i < 1000; i++ {
result := r.RangeUint64(1, 10)
assert.True(t, result >= 1)
assert.True(t, result <= 10)
}
}
func TestRandomizer_WeightedChoice_EmptyArray(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.WeightedChoice([]int{})
assert.Equal(t, -1, result)
}
func TestRandomizer_WeightedChoice_AllZeroWeights(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.WeightedChoice([]int{0, 0, 0})
assert.Equal(t, 2, result)
}
func TestRandomizer_WeightedChoice_MixedWeights(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
weightArray := []int{1, 0, 3, 0, 2}
counts := make([]int, len(weightArray))
for i := 0; i < 1000; i++ {
choice := r.WeightedChoice(weightArray)
counts[choice]++
}
assert.Greater(t, counts[0], 0)
assert.Greater(t, counts[2], 0)
assert.Greater(t, counts[4], 0)
}
func TestRandomizer_RandomString_LengthZero(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
result := r.RandomString(0)
assert.Equal(t, "", result)
}
func TestRandomizer_RandomString_CorrectLength(t *testing.T) {
r := NewRandomizer(UnixNanoSeed)
length := 50
result := r.RandomString(length)
assert.Equal(t, length, len(result))
}