diff --git a/common/utils/sqrt.go b/common/utils/sqrt.go new file mode 100644 index 00000000..88ee8307 --- /dev/null +++ b/common/utils/sqrt.go @@ -0,0 +1,63 @@ +package utils + +import ( + "math" +) + +// fastInvSqrt 实现了卡马克的快速平方根倒数算法 +func fastInvSqrt(x float32) float32 { + xhalf := float32(0.5) * x + i := math.Float32bits(x) // 将浮点数转换为32位整数 + i = 0x5f3759df - (i >> 1) // 神奇数字和位操作 + y := math.Float32frombits(i) // 将整数转换回浮点数 + y = y * (float32(1.5) - xhalf*y*y) // 牛顿迭代一步提高精度 + return y +} + +// fastSqrtCarmack 使用卡马克算法计算平方根 +func fastSqrtCarmack(x float64) float64 { + if x == 0 || math.IsNaN(x) || math.IsInf(x, 1) { + return x + } + if x < 0 { + return math.NaN() + } + + x32 := float32(x) + invSqrt := fastInvSqrt(x32) + return float64(x32) * float64(invSqrt) +} + +// fastSqrt 使用快速平方根倒数算法计算平方根 +func fastSqrt(x float64) float64 { + // 处理特殊情况 + if x == 0 || math.IsNaN(x) || math.IsInf(x, 1) { + return x + } + if x < 0 { + return math.NaN() + } + + // 转换为float32进行卡马克算法计算 + x32 := float32(x) + invSqrt := fastInvSqrt(x32) + + // 转回float64并计算平方根 + result := float64(x32) * float64(invSqrt) + return result +} + +// fastSqrtInt 实现了针对整数的快速平方根算法 +func fastSqrtInt(n int) int { + if n < 0 { + return 0 // 处理负数情况 + } + if n == 0 || n == 1 { + return n + } + + // 使用浮点数版本的快速平方根 + x := float64(n) + sqrt := fastSqrt(x) + return int(sqrt + 0.5) // 四舍五入转换为整数 +} diff --git a/common/utils/sqrt_test.go b/common/utils/sqrt_test.go new file mode 100644 index 00000000..95d0b55e --- /dev/null +++ b/common/utils/sqrt_test.go @@ -0,0 +1,91 @@ +package utils + +import ( + "fmt" + "math" + "testing" +) + +func Test_fastSqrt(t *testing.T) { + // 测试用例 + testCases := []float64{2, 4, 10, 16, 25, 100, 1000, 0.5, 0.01, 1e-20} + + fmt.Println("测试卡马克快速平方根算法与标准库的对比:") + fmt.Println("数值\t快速算法结果\t标准库结果\t绝对误差") + fmt.Println("--------------------------------------------------------------") + + for _, x := range testCases { + fastResult := fastSqrt(x) + stdResult := math.Sqrt(x) + error := math.Abs(fastResult - stdResult) + + fmt.Printf("%.10g\t%.10g\t\t%.10g\t\t%.2e\n", + x, fastResult, stdResult, error) + } + + // 测试整数版本 + fmt.Println("\n测试整数快速平方根算法:") + fmt.Println("数值\t快速算法结果\t标准库转换结果") + fmt.Println("--------------------------------------") + + for _, x := range []int{2, 4, 10, 16, 25, 100, 1000} { + fastResult := fastSqrtInt(x) + stdResult := int(math.Sqrt(float64(x))) + + fmt.Printf("%d\t%d\t\t%d\n", x, fastResult, stdResult) + } +} +func BenchmarkMathSqrt(b *testing.B) { + testValues := []float64{2, 4, 10, 16, 25, 100, 1000, 0.5, 0.01, 1e-20} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, x := range testValues { + _ = math.Sqrt(x) + } + } +} + +func BenchmarkFastSqrt(b *testing.B) { + testValues := []float64{2, 4, 10, 16, 25, 100, 1000, 0.5, 0.01, 1e-20} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, x := range testValues { + _ = fastSqrt(x) + } + } +} + +func BenchmarkFastSqrtCarmack(b *testing.B) { + testValues := []float64{2, 4, 10, 16, 25, 100, 1000, 0.5, 0.01, 1e-20} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, x := range testValues { + _ = fastSqrtCarmack(x) + } + } +} + +func BenchmarkMathSqrtInt(b *testing.B) { + testValues := []int{2, 4, 10, 16, 25, 100, 1000, 10000, 100000} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, x := range testValues { + _ = int(math.Sqrt(float64(x))) + } + } +} + +func BenchmarkFastSqrtInt(b *testing.B) { + testValues := []int{2, 4, 10, 16, 25, 100, 1000, 10000, 100000} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, x := range testValues { + _ = fastSqrtInt(x) + } + } +}