feat: math.
This commit is contained in:
27
math/math.go
27
math/math.go
@@ -42,3 +42,30 @@ func StandardDeviation(num []float64) float64 {
|
||||
var variance = Variance(mean, num)
|
||||
return math.Sqrt(variance)
|
||||
}
|
||||
|
||||
// SumInt 计算整数数组的和
|
||||
func SumInt[T int | int32 | int64](array []T) int64 {
|
||||
var sum int64
|
||||
for _, v := range array {
|
||||
sum = sum + int64(v)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// SumUint 计算整数数组的和
|
||||
func SumUint[T uint | uint32 | uint64](array []T) uint64 {
|
||||
var sum uint64
|
||||
for _, v := range array {
|
||||
sum = sum + uint64(v)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// SumFloat 计算浮点数数组的和
|
||||
func SumFloat[T float32 | float64](array []T) float64 {
|
||||
var sum float64
|
||||
for _, v := range array {
|
||||
sum = sum + float64(v)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
131
rand/rand.go
131
rand/rand.go
@@ -3,16 +3,50 @@ package rand
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/tx7do/go-utils/math"
|
||||
)
|
||||
|
||||
var RANDOM = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
func init() {
|
||||
rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
func Float32() float32 {
|
||||
return rnd.Float32()
|
||||
}
|
||||
|
||||
func Float64() float64 {
|
||||
return rnd.Float64()
|
||||
}
|
||||
|
||||
func Intn(n int) int {
|
||||
return rnd.Intn(n)
|
||||
}
|
||||
|
||||
func Int31n(n int32) int32 {
|
||||
return rnd.Int31n(n)
|
||||
}
|
||||
|
||||
func Int63n(n int64) int64 {
|
||||
return rnd.Int63n(n)
|
||||
}
|
||||
|
||||
// RandomInt 根据区间产生随机数
|
||||
func RandomInt(min, max int) int {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return RANDOM.Intn(max-min) + min
|
||||
return min + Intn(max-min+1)
|
||||
}
|
||||
|
||||
// RandomInt32 根据区间产生随机数
|
||||
func RandomInt32(min, max int32) int32 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return min + Int31n(max-min+1)
|
||||
}
|
||||
|
||||
// RandomInt64 根据区间产生随机数
|
||||
@@ -20,5 +54,96 @@ func RandomInt64(min, max int64) int64 {
|
||||
if min >= max {
|
||||
return max
|
||||
}
|
||||
return RANDOM.Int63n(max-min) + min
|
||||
return min + Int63n(max-min+1)
|
||||
}
|
||||
|
||||
// RandomString 随机字符串,包含大小写字母和数字
|
||||
func RandomString(l int) string {
|
||||
bytes := make([]byte, l)
|
||||
for i := 0; i < l; i++ {
|
||||
x := Intn(3)
|
||||
switch x {
|
||||
case 0:
|
||||
bytes[i] = byte(RandomInt(65, 90)) //大写字母
|
||||
case 1:
|
||||
bytes[i] = byte(RandomInt(97, 122))
|
||||
case 2:
|
||||
bytes[i] = byte(Intn(10))
|
||||
}
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// RandomChoice 随机选择数组中的元素
|
||||
func RandomChoice[T any](array []T, n int) []T {
|
||||
if n <= 0 {
|
||||
return nil
|
||||
}
|
||||
if n == 1 {
|
||||
return []T{array[Intn(len(array))]}
|
||||
}
|
||||
|
||||
tmp := make([]T, len(array))
|
||||
copy(tmp, array)
|
||||
if len(tmp) <= n {
|
||||
return tmp
|
||||
}
|
||||
|
||||
Shuffle(tmp)
|
||||
|
||||
return tmp[:n]
|
||||
}
|
||||
|
||||
// Shuffle 随机打乱数组
|
||||
func Shuffle[T any](array []T) {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range array {
|
||||
j := Intn(i + 1)
|
||||
array[i], array[j] = array[j], array[i]
|
||||
}
|
||||
}
|
||||
|
||||
// WeightedChoice 根据权重随机,返回对应选项的索引,O(n)
|
||||
func WeightedChoice(weightArray []int) int {
|
||||
if weightArray == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
total := math.SumInt(weightArray)
|
||||
rv := 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 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 := Int63n(total)
|
||||
for i, v := range weightArray {
|
||||
if rv < int64(v) {
|
||||
return i
|
||||
}
|
||||
rv -= int64(v)
|
||||
}
|
||||
|
||||
return len(weightArray) - 1
|
||||
}
|
||||
|
||||
@@ -7,11 +7,286 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRandomInt(t *testing.T) {
|
||||
func TestFloat32_GeneratesValueWithinRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
n := RandomInt(1, 100)
|
||||
fmt.Println(n)
|
||||
assert.True(t, n >= 1)
|
||||
assert.True(t, n < 100)
|
||||
value := Float32()
|
||||
assert.True(t, value >= 0.0)
|
||||
assert.True(t, value < 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32_GeneratesDifferentValues(t *testing.T) {
|
||||
values := make(map[float32]bool)
|
||||
for i := 0; i < 1000; i++ {
|
||||
value := Float32()
|
||||
values[value] = true
|
||||
}
|
||||
assert.Greater(t, len(values), 1)
|
||||
}
|
||||
|
||||
func TestFloat64_GeneratesValueWithinRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
value := Float64()
|
||||
assert.True(t, value >= 0.0)
|
||||
assert.True(t, value < 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64_GeneratesDifferentValues(t *testing.T) {
|
||||
values := make(map[float64]bool)
|
||||
for i := 0; i < 1000; i++ {
|
||||
value := Float64()
|
||||
values[value] = true
|
||||
}
|
||||
assert.Greater(t, len(values), 1)
|
||||
}
|
||||
|
||||
func TestRandomInt(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
n := RandomInt(1, 10)
|
||||
fmt.Println(n)
|
||||
assert.True(t, n >= 1)
|
||||
assert.True(t, n <= 100)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt_MinEqualsMax(t *testing.T) {
|
||||
n := RandomInt(5, 5)
|
||||
assert.Equal(t, 5, n)
|
||||
}
|
||||
|
||||
func TestRandomInt_MinGreaterThanMax(t *testing.T) {
|
||||
n := RandomInt(10, 5)
|
||||
assert.Equal(t, 5, n)
|
||||
}
|
||||
|
||||
func TestRandomInt_NegativeRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
n := RandomInt(-10, -1)
|
||||
assert.True(t, n >= -10)
|
||||
assert.True(t, n <= -1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt_ZeroRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
n := RandomInt(0, 0)
|
||||
assert.Equal(t, 0, n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShuffle_EmptyArray(t *testing.T) {
|
||||
var array []int
|
||||
Shuffle(array)
|
||||
assert.Equal(t, array, array)
|
||||
}
|
||||
|
||||
func TestShuffle_SingleElementArray(t *testing.T) {
|
||||
array := []int{1}
|
||||
Shuffle(array)
|
||||
assert.Equal(t, []int{1}, array)
|
||||
}
|
||||
|
||||
func TestShuffle_MultipleElementsArray(t *testing.T) {
|
||||
array := []int{1, 2, 3, 4, 5}
|
||||
original := make([]int, len(array))
|
||||
copy(original, array)
|
||||
Shuffle(array)
|
||||
assert.ElementsMatch(t, original, array)
|
||||
}
|
||||
|
||||
func TestShuffle_ArrayWithDuplicates(t *testing.T) {
|
||||
array := []int{1, 2, 2, 3, 3, 3}
|
||||
original := make([]int, len(array))
|
||||
copy(original, array)
|
||||
Shuffle(array)
|
||||
fmt.Println(array)
|
||||
assert.ElementsMatch(t, original, array)
|
||||
}
|
||||
|
||||
func TestRandomChoice_EmptyArray(t *testing.T) {
|
||||
result := RandomChoice([]int{}, 3)
|
||||
assert.Nil(t, result)
|
||||
}
|
||||
|
||||
func TestRandomChoice_NegativeN(t *testing.T) {
|
||||
array := []int{1, 2, 3}
|
||||
result := RandomChoice(array, -1)
|
||||
assert.Nil(t, result)
|
||||
}
|
||||
|
||||
func TestRandomChoice_ZeroN(t *testing.T) {
|
||||
array := []int{1, 2, 3}
|
||||
result := RandomChoice(array, 0)
|
||||
assert.Nil(t, result)
|
||||
}
|
||||
|
||||
func TestRandomChoice_NGreaterThanArrayLength(t *testing.T) {
|
||||
array := []int{1, 2, 3}
|
||||
result := RandomChoice(array, 5)
|
||||
assert.ElementsMatch(t, array, result)
|
||||
}
|
||||
|
||||
func TestRandomChoice_NEqualToArrayLength(t *testing.T) {
|
||||
array := []int{1, 2, 3}
|
||||
result := RandomChoice(array, 3)
|
||||
assert.ElementsMatch(t, array, result)
|
||||
}
|
||||
|
||||
func TestRandomChoice_NLessThanArrayLength(t *testing.T) {
|
||||
array := []int{1, 2, 3, 4, 5}
|
||||
result := RandomChoice(array, 3)
|
||||
assert.Len(t, result, 3)
|
||||
}
|
||||
|
||||
func TestRandomInt32_MinEqualsMax(t *testing.T) {
|
||||
result := RandomInt32(5, 5)
|
||||
assert.Equal(t, int32(5), result)
|
||||
}
|
||||
|
||||
func TestRandomInt32_MinGreaterThanMax(t *testing.T) {
|
||||
result := RandomInt32(10, 5)
|
||||
assert.Equal(t, int32(5), result)
|
||||
}
|
||||
|
||||
func TestRandomInt32_PositiveRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := RandomInt32(1, 10)
|
||||
assert.True(t, result >= 1)
|
||||
assert.True(t, result <= 10)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt32_NegativeRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := RandomInt32(-10, -1)
|
||||
assert.True(t, result >= -10)
|
||||
assert.True(t, result <= -1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt32_ZeroRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := RandomInt32(0, 0)
|
||||
assert.Equal(t, int32(0), result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt64_MinEqualsMax(t *testing.T) {
|
||||
result := RandomInt64(5, 5)
|
||||
assert.Equal(t, int64(5), result)
|
||||
}
|
||||
|
||||
func TestRandomInt64_MinGreaterThanMax(t *testing.T) {
|
||||
result := RandomInt64(10, 5)
|
||||
assert.Equal(t, int64(5), result)
|
||||
}
|
||||
|
||||
func TestRandomInt64_PositiveRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := RandomInt64(1, 10)
|
||||
assert.True(t, result >= 1)
|
||||
assert.True(t, result <= 10)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt64_NegativeRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := RandomInt64(-10, -1)
|
||||
assert.True(t, result >= -10)
|
||||
assert.True(t, result <= -1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomInt64_ZeroRange(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
result := RandomInt64(0, 0)
|
||||
assert.Equal(t, int64(0), result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomString_LengthZero(t *testing.T) {
|
||||
result := RandomString(0)
|
||||
assert.Equal(t, "", result)
|
||||
}
|
||||
|
||||
func TestRandomString_PositiveLength(t *testing.T) {
|
||||
result := RandomString(10)
|
||||
assert.Len(t, result, 10)
|
||||
}
|
||||
|
||||
func TestRandomString_ContainsOnlyValidCharacters(t *testing.T) {
|
||||
result := RandomString(100)
|
||||
for _, char := range result {
|
||||
assert.True(t, (char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9'))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomString_NegativeLength(t *testing.T) {
|
||||
result := RandomString(-5)
|
||||
assert.Equal(t, "", result)
|
||||
}
|
||||
|
||||
func TestWeightedChoice_EmptyArray(t *testing.T) {
|
||||
result := WeightedChoice([]int{})
|
||||
assert.Equal(t, -1, result)
|
||||
}
|
||||
|
||||
func TestWeightedChoice_AllZeroWeights(t *testing.T) {
|
||||
result := WeightedChoice([]int{0, 0, 0})
|
||||
assert.Equal(t, 2, result)
|
||||
}
|
||||
|
||||
func TestWeightedChoice_NegativeWeights(t *testing.T) {
|
||||
result := WeightedChoice([]int{-1, -2, -3})
|
||||
assert.Equal(t, 2, result)
|
||||
}
|
||||
|
||||
func TestWeightedChoice_MixedWeights(t *testing.T) {
|
||||
weightArray := []int{1, 0, 3, 0, 2}
|
||||
counts := make([]int, len(weightArray))
|
||||
for i := 0; i < 1000; i++ {
|
||||
choice := WeightedChoice(weightArray)
|
||||
counts[choice]++
|
||||
}
|
||||
assert.Greater(t, counts[0], 0)
|
||||
assert.Greater(t, counts[2], 0)
|
||||
assert.Greater(t, counts[4], 0)
|
||||
}
|
||||
|
||||
func TestWeightedChoice_SingleElement(t *testing.T) {
|
||||
result := WeightedChoice([]int{5})
|
||||
assert.Equal(t, 0, result)
|
||||
}
|
||||
|
||||
func TestNonWeightedChoice_EmptyArray(t *testing.T) {
|
||||
result := NonWeightedChoice([]int{})
|
||||
assert.Equal(t, -1, result)
|
||||
}
|
||||
|
||||
func TestNonWeightedChoice_AllZeroWeights(t *testing.T) {
|
||||
result := NonWeightedChoice([]int{0, 0, 0})
|
||||
assert.Equal(t, 2, result)
|
||||
}
|
||||
|
||||
func TestNonWeightedChoice_NegativeWeights(t *testing.T) {
|
||||
result := NonWeightedChoice([]int{-1, -2, -3})
|
||||
assert.Equal(t, 2, result)
|
||||
}
|
||||
|
||||
func TestNonWeightedChoice_MixedWeights(t *testing.T) {
|
||||
weightArray := []int{1, 0, 3, 0, 2}
|
||||
counts := make([]int, len(weightArray))
|
||||
for i := 0; i < 1000; i++ {
|
||||
choice := NonWeightedChoice(weightArray)
|
||||
counts[choice]++
|
||||
}
|
||||
assert.Greater(t, counts[0], 0)
|
||||
assert.Greater(t, counts[2], 0)
|
||||
assert.Greater(t, counts[4], 0)
|
||||
}
|
||||
|
||||
func TestNonWeightedChoice_SingleElement(t *testing.T) {
|
||||
result := NonWeightedChoice([]int{5})
|
||||
assert.Equal(t, 0, result)
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package uuid
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package uuid
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/tx7do/go-utils/trans"
|
||||
)
|
||||
|
||||
66
uuid/uuid_test.go
Normal file
66
uuid/uuid_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
t.Run("ToUuidPtr_NilString", func(t *testing.T) {
|
||||
var str *string
|
||||
result := ToUuidPtr(str)
|
||||
if result != nil {
|
||||
t.Errorf("expected nil, got %v", result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ToUuidPtr_ValidString", func(t *testing.T) {
|
||||
str := "550e8400-e29b-41d4-a716-446655440000"
|
||||
result := ToUuidPtr(&str)
|
||||
if result == nil || result.String() != str {
|
||||
t.Errorf("expected %v, got %v", str, result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ToUuidPtr_InvalidString", func(t *testing.T) {
|
||||
str := "invalid-uuid"
|
||||
result := ToUuidPtr(&str)
|
||||
if result != nil {
|
||||
t.Errorf("expected nil, got %v", result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ToUuid_ValidString", func(t *testing.T) {
|
||||
str := "550e8400-e29b-41d4-a716-446655440000"
|
||||
result := ToUuid(str)
|
||||
if result.String() != str {
|
||||
t.Errorf("expected %v, got %v", str, result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ToUuid_InvalidString", func(t *testing.T) {
|
||||
str := "invalid-uuid"
|
||||
result := ToUuid(str)
|
||||
if result.String() == str {
|
||||
t.Errorf("expected invalid UUID, got %v", result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ToStringPtr_NilUUID", func(t *testing.T) {
|
||||
var id *uuid.UUID
|
||||
result := ToStringPtr(id)
|
||||
if result != nil {
|
||||
t.Errorf("expected nil, got %v", result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ToStringPtr_ValidUUID", func(t *testing.T) {
|
||||
id := uuid.MustParse("550e8400-e29b-41d4-a716-446655440000")
|
||||
result := ToStringPtr(&id)
|
||||
expected := "550e8400-e29b-41d4-a716-446655440000"
|
||||
if result == nil || *result != expected {
|
||||
t.Errorf("expected %v, got %v", expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user