feat: math.

This commit is contained in:
tx7do
2024-09-23 21:31:56 +08:00
parent 8d39ab89d9
commit f7abc4e941
6 changed files with 502 additions and 15 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -1,7 +0,0 @@
package uuid
import "testing"
func TestUUID(t *testing.T) {
}

View File

@@ -2,6 +2,7 @@ package uuid
import (
"github.com/google/uuid"
"github.com/tx7do/go-utils/trans"
)

66
uuid/uuid_test.go Normal file
View 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)
}
})
}