Go 语言 math 包使用教程
Go 语言的 math 包提供了基本的数学常量和数学函数,是进行数值计算的核心工具包。
1. 基础概念
在 Go 的 math 模块中,核心概念包括:
- 数学常量: 如 π、e、黄金比例等重要数学常量。
- 基本运算: 幂运算、开方、对数、三角函数等。
- 数值处理: 取整、绝对值、最大最小值等。
- 特殊函数: 伽马函数、贝塞尔函数等高级数学函数。
- 浮点数处理: NaN、无穷大等特殊值的处理。
math 包的子包
Go 的 math 包还包含以下重要子包:
math/big: 任意精度算术运算math/cmplx: 复数运算math/rand: 伪随机数生成math/bits: 位操作函数
为什么使用 math 包?
虽然 Go 提供了基本的算术运算符,但 math 包提供了更强大的数学计算能力:
- 精确计算: 提供高精度的数学函数实现
- 丰富功能: 涵盖了大部分常用的数学运算
- 性能优化: 底层实现经过优化
- 标准库: 稳定可靠,跨平台兼容
2. 数学常量
重要的数学常量
Go 的 math 包预定义了许多重要的数学常量:
go
package main
import (
"fmt"
"math"
)
func main() {
// 基本数学常量
fmt.Printf("π (Pi): %.10f\n", math.Pi)
fmt.Printf("e (自然对数底): %.10f\n", math.E)
fmt.Printf("φ (黄金比例): %.10f\n", math.Phi)
// 对数相关常量
fmt.Printf("ln(2): %.10f\n", math.Ln2)
fmt.Printf("ln(10): %.10f\n", math.Ln10)
fmt.Printf("log₂(e): %.10f\n", math.Log2E)
fmt.Printf("log₁₀(e): %.10f\n", math.Log10E)
// 平方根常量
fmt.Printf("√2: %.10f\n", math.Sqrt2)
fmt.Printf("√e: %.10f\n", math.SqrtE)
fmt.Printf("√π: %.10f\n", math.SqrtPi)
fmt.Printf("√φ: %.10f\n", math.SqrtPhi)
// 特殊值
fmt.Printf("正无穷: %v\n", math.Inf(1))
fmt.Printf("负无穷: %v\n", math.Inf(-1))
fmt.Printf("NaN: %v\n", math.NaN())
}运行结果:
shell
π (Pi): 3.1415926536
e (自然对数底): 2.7182818285
φ (黄金比例): 1.6180339887
ln(2): 0.6931471806
ln(10): 2.3025850930
log₂(e): 1.4426950409
log₁₀(e): 0.4342944819
√2: 1.4142135624
√e: 1.6487212707
√π: 1.7724538509
√φ: 1.2720196495
正无穷: +Inf
负无穷: -Inf
NaN: NaN浮点数限制常量
了解浮点数的精度和范围限制:
go
package main
import (
"fmt"
"math"
)
func main() {
// float64 的限制
fmt.Printf("float64 最大值: %e\n", math.MaxFloat64)
fmt.Printf("float64 最小正值: %e\n", math.SmallestNonzeroFloat64)
// float32 的限制
fmt.Printf("float32 最大值: %e\n", math.MaxFloat32)
fmt.Printf("float32 最小正值: %e\n", math.SmallestNonzeroFloat32)
// 整数限制
fmt.Printf("int8 最大值: %d\n", math.MaxInt8)
fmt.Printf("int16 最大值: %d\n", math.MaxInt16)
fmt.Printf("int32 最大值: %d\n", math.MaxInt32)
fmt.Printf("int64 最大值: %d\n", math.MaxInt64)
fmt.Printf("uint8 最大值: %d\n", math.MaxUint8)
fmt.Printf("uint16 最大值: %d\n", math.MaxUint16)
fmt.Printf("uint32 最大值: %d\n", math.MaxUint32)
fmt.Printf("uint64 最大值: %d\n", uint64(math.MaxUint64))
}3. 基本数学运算
幂运算和开方
常用的指数和根运算:
go
package main
import (
"fmt"
"math"
)
func main() {
x := 16.0
y := 3.0
// 幂运算
fmt.Printf("%.1f^%.1f = %.2f\n", x, y, math.Pow(x, y))
fmt.Printf("%.1f² = %.2f\n", x, math.Pow(x, 2))
fmt.Printf("2^%.1f = %.2f\n", x, math.Pow(2, x))
// 开方运算
fmt.Printf("√%.1f = %.2f\n", x, math.Sqrt(x))
fmt.Printf("∛%.1f = %.2f\n", x, math.Cbrt(x))
// 特殊幂运算
fmt.Printf("2^%.1f = %.2f\n", y, math.Exp2(y)) // 2的y次方
fmt.Printf("10^%.1f = %.2f\n", y, math.Pow10(int(y))) // 10的y次方
fmt.Printf("e^%.1f = %.2f\n", y, math.Exp(y)) // e的y次方
// 平方根的倒数
fmt.Printf("1/√%.1f = %.4f\n", x, 1/math.Sqrt(x))
// 计算斜边长度(勾股定理)
a, b := 3.0, 4.0
fmt.Printf("直角三角形斜边长度 (%.1f, %.1f): %.2f\n", a, b, math.Hypot(a, b))
}运行结果:
shell
16.0^3.0 = 4096.00
16.0² = 256.00
2^16.0 = 65536.00
√16.0 = 4.00
∛16.0 = 2.52
2^3.0 = 8.00
10^3.0 = 1000.00
e^3.0 = 20.09
1/√16.0 = 0.2500
直角三角形斜边长度 (3.0, 4.0): 5.00对数运算
各种对数函数的使用:
go
package main
import (
"fmt"
"math"
)
func main() {
x := 100.0
// 基本对数
fmt.Printf("ln(%.1f) = %.4f\n", x, math.Log(x)) // 自然对数
fmt.Printf("log₂(%.1f) = %.4f\n", x, math.Log2(x)) // 以2为底
fmt.Printf("log₁₀(%.1f) = %.4f\n", x, math.Log10(x)) // 以10为底
// 特殊对数函数
y := 1.5
fmt.Printf("ln(1 + %.1f) = %.4f\n", y, math.Log1p(y)) // ln(1+x),更精确
// 验证对数和指数的关系
original := 42.0
logged := math.Log(original)
restored := math.Exp(logged)
fmt.Printf("原值: %.1f, ln后: %.4f, exp后: %.1f\n", original, logged, restored)
// 实际应用:计算复合增长率
initialValue := 1000.0
finalValue := 2000.0
years := 5.0
growthRate := math.Log(finalValue/initialValue) / years
fmt.Printf("年复合增长率: %.2f%%\n", growthRate*100)
}4. 三角函数
基本三角函数
正弦、余弦、正切及其反函数:
go
package main
import (
"fmt"
"math"
)
func main() {
// 角度转弧度的辅助函数
deg2rad := func(deg float64) float64 {
return deg * math.Pi / 180
}
// 弧度转角度的辅助函数
rad2deg := func(rad float64) float64 {
return rad * 180 / math.Pi
}
// 常用角度的三角函数值
angles := []float64{0, 30, 45, 60, 90}
fmt.Println("角度\t弧度\t\tsin\t\tcos\t\ttan")
fmt.Println("----\t----\t\t---\t\t---\t\t---")
for _, angle := range angles {
rad := deg2rad(angle)
sin := math.Sin(rad)
cos := math.Cos(rad)
tan := math.Tan(rad)
fmt.Printf("%.0f°\t%.4f\t\t%.4f\t\t%.4f\t\t", angle, rad, sin, cos)
if math.Abs(tan) > 1000 {
fmt.Println("∞")
} else {
fmt.Printf("%.4f\n", tan)
}
}
// 反三角函数
fmt.Println("\n反三角函数示例:")
x := 0.5
fmt.Printf("arcsin(%.1f) = %.2f° (%.4f rad)\n", x, rad2deg(math.Asin(x)), math.Asin(x))
fmt.Printf("arccos(%.1f) = %.2f° (%.4f rad)\n", x, rad2deg(math.Acos(x)), math.Acos(x))
fmt.Printf("arctan(%.1f) = %.2f° (%.4f rad)\n", x, rad2deg(math.Atan(x)), math.Atan(x))
// atan2 函数 - 考虑象限的反正切
y, x := 1.0, 1.0
fmt.Printf("atan2(%.1f, %.1f) = %.2f° (第一象限)\n", y, x, rad2deg(math.Atan2(y, x)))
y, x = 1.0, -1.0
fmt.Printf("atan2(%.1f, %.1f) = %.2f° (第二象限)\n", y, x, rad2deg(math.Atan2(y, x)))
}双曲函数
双曲正弦、余弦、正切函数:
go
package main
import (
"fmt"
"math"
)
func main() {
x := 1.0
// 双曲函数
fmt.Printf("sinh(%.1f) = %.4f\n", x, math.Sinh(x))
fmt.Printf("cosh(%.1f) = %.4f\n", x, math.Cosh(x))
fmt.Printf("tanh(%.1f) = %.4f\n", x, math.Tanh(x))
// 反双曲函数
fmt.Printf("asinh(%.1f) = %.4f\n", x, math.Asinh(x))
fmt.Printf("acosh(%.1f) = %.4f\n", x+1, math.Acosh(x+1)) // acosh需要x>=1
fmt.Printf("atanh(%.1f) = %.4f\n", x/2, math.Atanh(x/2)) // atanh需要|x|<1
// 验证双曲函数恒等式: cosh²(x) - sinh²(x) = 1
cosh := math.Cosh(x)
sinh := math.Sinh(x)
identity := cosh*cosh - sinh*sinh
fmt.Printf("验证恒等式 cosh²(%.1f) - sinh²(%.1f) = %.6f\n", x, x, identity)
}5. 数值处理函数
取整和舍入
各种取整方式的使用:
go
package main
import (
"fmt"
"math"
)
func main() {
numbers := []float64{3.2, 3.7, -2.3, -2.8, 0.5, -0.5}
fmt.Println("数值\t\tFloor\tCeil\tTrunc\tRound")
fmt.Println("----\t\t-----\t----\t-----\t-----")
for _, num := range numbers {
floor := math.Floor(num) // 向下取整
ceil := math.Ceil(num) // 向上取整
trunc := math.Trunc(num) // 截断小数部分
round := math.Round(num) // 四舍五入
fmt.Printf("%.1f\t\t%.0f\t%.0f\t%.0f\t%.0f\n", num, floor, ceil, trunc, round)
}
// 获取小数部分和整数部分
fmt.Println("\n分离整数和小数部分:")
for _, num := range []float64{3.14, -2.71} {
integer, fraction := math.Modf(num)
fmt.Printf("%.2f = %.0f + %.2f\n", num, integer, fraction)
}
// 实际应用:价格计算
price := 19.99
taxRate := 0.08
totalPrice := price * (1 + taxRate)
fmt.Printf("\n价格计算示例:\n")
fmt.Printf("商品价格: $%.2f\n", price)
fmt.Printf("税率: %.1f%%\n", taxRate*100)
fmt.Printf("含税价格: $%.2f\n", totalPrice)
fmt.Printf("四舍五入到分: $%.2f\n", math.Round(totalPrice*100)/100)
}绝对值和符号
处理数值的符号和绝对值:
go
package main
import (
"fmt"
"math"
)
func main() {
numbers := []float64{3.14, -2.71, 0, -0.0}
fmt.Println("数值\t\t绝对值\t\t符号")
fmt.Println("----\t\t------\t\t----")
for _, num := range numbers {
abs := math.Abs(num)
sign := math.Signbit(num)
fmt.Printf("%.2f\t\t%.2f\t\t", num, abs)
if sign {
fmt.Println("负数")
} else {
fmt.Println("正数")
}
}
// Copysign - 复制符号
fmt.Println("\nCopysign 示例:")
x, y := 3.14, -2.0
result := math.Copysign(x, y)
fmt.Printf("Copysign(%.2f, %.1f) = %.2f\n", x, y, result)
// 实际应用:计算两点间距离
x1, y1 := 1.0, 2.0
x2, y2 := 4.0, 6.0
distance := math.Sqrt(math.Pow(math.Abs(x2-x1), 2) + math.Pow(math.Abs(y2-y1), 2))
fmt.Printf("点(%.1f,%.1f)到点(%.1f,%.1f)的距离: %.2f\n", x1, y1, x2, y2, distance)
}6. 最大值和最小值
比较函数
查找最大值和最小值:
go
package main
import (
"fmt"
"math"
)
func main() {
// 基本的最大值和最小值
a, b := 3.14, 2.71
fmt.Printf("max(%.2f, %.2f) = %.2f\n", a, b, math.Max(a, b))
fmt.Printf("min(%.2f, %.2f) = %.2f\n", a, b, math.Min(a, b))
// 处理特殊值
fmt.Printf("max(NaN, 1.0) = %.2f\n", math.Max(math.NaN(), 1.0))
fmt.Printf("max(+Inf, 1.0) = %v\n", math.Max(math.Inf(1), 1.0))
// 实际应用:找到切片中的最大值和最小值
numbers := []float64{3.14, 2.71, 1.41, 1.73, 2.23}
if len(numbers) > 0 {
maxVal := numbers[0]
minVal := numbers[0]
for _, num := range numbers[1:] {
maxVal = math.Max(maxVal, num)
minVal = math.Min(minVal, num)
}
fmt.Printf("\n数组 %v\n", numbers)
fmt.Printf("最大值: %.2f\n", maxVal)
fmt.Printf("最小值: %.2f\n", minVal)
fmt.Printf("范围: %.2f\n", maxVal-minVal)
}
// 限制数值范围(clamp 函数)
clamp := func(value, min, max float64) float64 {
return math.Max(min, math.Min(max, value))
}
fmt.Println("\n数值范围限制示例:")
testValues := []float64{-5, 0, 5, 10, 15}
minRange, maxRange := 0.0, 10.0
for _, val := range testValues {
clamped := clamp(val, minRange, maxRange)
fmt.Printf("clamp(%.0f, %.0f, %.0f) = %.0f\n", val, minRange, maxRange, clamped)
}
}7. 特殊函数
伽马函数和相关函数
高级数学函数的使用:
go
package main
import (
"fmt"
"math"
)
func main() {
// 伽马函数
fmt.Println("伽马函数示例:")
for i := 1; i <= 5; i++ {
x := float64(i)
gamma := math.Gamma(x)
fmt.Printf("Γ(%.0f) = %.6f\n", x, gamma)
}
// 对数伽马函数
x := 10.0
logGamma, sign := math.Lgamma(x)
fmt.Printf("ln|Γ(%.0f)| = %.6f, sign = %.0f\n", x, logGamma, sign)
// 误差函数
fmt.Println("\n误差函数示例:")
values := []float64{0, 0.5, 1.0, 1.5, 2.0}
for _, val := range values {
erf := math.Erf(val)
erfc := math.Erfc(val)
fmt.Printf("erf(%.1f) = %.6f, erfc(%.1f) = %.6f\n", val, erf, val, erfc)
}
// J0, J1 贝塞尔函数
fmt.Println("\n贝塞尔函数示例:")
for _, val := range []float64{0, 1, 2, 5} {
j0 := math.J0(val)
j1 := math.J1(val)
fmt.Printf("J₀(%.0f) = %.6f, J₁(%.0f) = %.6f\n", val, j0, val, j1)
}
}浮点数操作
处理浮点数的特殊情况:
go
package main
import (
"fmt"
"math"
)
func main() {
// 检查特殊值
values := []float64{1.0, math.Inf(1), math.Inf(-1), math.NaN(), 0.0}
fmt.Println("值\t\tIsNaN\tIsInf\tIsInf(+)\tIsInf(-)")
fmt.Println("---\t\t-----\t-----\t--------\t--------")
for _, val := range values {
isNaN := math.IsNaN(val)
isInf := math.IsInf(val, 0)
isPosInf := math.IsInf(val, 1)
isNegInf := math.IsInf(val, -1)
fmt.Printf("%v\t\t%v\t%v\t%v\t\t%v\n", val, isNaN, isInf, isPosInf, isNegInf)
}
// 浮点数分解
fmt.Println("\n浮点数分解:")
x := 3.14159
frac, exp := math.Frexp(x)
fmt.Printf("%.5f = %.5f × 2^%d\n", x, frac, exp)
// 重新组合
reconstructed := math.Ldexp(frac, exp)
fmt.Printf("重新组合: %.5f × 2^%d = %.5f\n", frac, exp, reconstructed)
// 获取浮点数的各个部分
fmt.Println("\n浮点数详细信息:")
testVal := -123.456
fmt.Printf("原值: %f\n", testVal)
fmt.Printf("符号位: %v\n", math.Signbit(testVal))
mantissa, exponent := math.Frexp(math.Abs(testVal))
fmt.Printf("尾数: %.10f\n", mantissa)
fmt.Printf("指数: %d\n", exponent)
}8. math 子包详解
math/big - 任意精度运算
处理超出标准类型范围的大数运算:
go
package main
import (
"fmt"
"math/big"
)
func main() {
// 大整数运算
fmt.Println("=== 大整数运算 ===")
// 创建大整数
a := big.NewInt(123456789)
b := big.NewInt(987654321)
// 基本运算
sum := new(big.Int).Add(a, b)
product := new(big.Int).Mul(a, b)
fmt.Printf("a = %s\n", a.String())
fmt.Printf("b = %s\n", b.String())
fmt.Printf("a + b = %s\n", sum.String())
fmt.Printf("a × b = %s\n", product.String())
// 计算阶乘
factorial := func(n int64) *big.Int {
result := big.NewInt(1)
for i := int64(2); i <= n; i++ {
result.Mul(result, big.NewInt(i))
}
return result
}
fmt.Printf("20! = %s\n", factorial(20).String())
// 大浮点数运算
fmt.Println("\n=== 大浮点数运算 ===")
// 设置精度为 100 位
x := big.NewFloat(0).SetPrec(100)
y := big.NewFloat(0).SetPrec(100)
x.SetString("3.1415926535897932384626433832795028841971693993751")
y.SetString("2.7182818284590452353602874713526624977572470937000")
result := big.NewFloat(0).SetPrec(100)
result.Add(x, y)
fmt.Printf("π = %s\n", x.Text('f', 50))
fmt.Printf("e = %s\n", y.Text('f', 50))
fmt.Printf("π + e = %s\n", result.Text('f', 50))
// 大有理数运算
fmt.Println("\n=== 大有理数运算 ===")
r1 := big.NewRat(1, 3) // 1/3
r2 := big.NewRat(2, 7) // 2/7
sum_rat := new(big.Rat).Add(r1, r2)
product_rat := new(big.Rat).Mul(r1, r2)
fmt.Printf("1/3 + 2/7 = %s\n", sum_rat.String())
fmt.Printf("1/3 × 2/7 = %s\n", product_rat.String())
fmt.Printf("1/3 + 2/7 = %f (浮点数近似)\n", sum_rat.Float64())
}math/cmplx - 复数运算
处理复数的各种数学运算:
go
package main
import (
"fmt"
"math"
"math/cmplx"
)
func main() {
// 创建复数
z1 := complex(3, 4) // 3 + 4i
z2 := complex(1, -2) // 1 - 2i
fmt.Printf("z1 = %.1f\n", z1)
fmt.Printf("z2 = %.1f\n", z2)
// 基本运算
fmt.Println("\n=== 基本复数运算 ===")
fmt.Printf("z1 + z2 = %.1f\n", z1+z2)
fmt.Printf("z1 - z2 = %.1f\n", z1-z2)
fmt.Printf("z1 × z2 = %.1f\n", z1*z2)
fmt.Printf("z1 ÷ z2 = %.2f\n", z1/z2)
// 复数函数
fmt.Println("\n=== 复数函数 ===")
fmt.Printf("abs(z1) = %.2f\n", cmplx.Abs(z1)) // 模长
fmt.Printf("phase(z1) = %.2f rad\n", cmplx.Phase(z1)) // 幅角
fmt.Printf("conj(z1) = %.1f\n", cmplx.Conj(z1)) // 共轭
// 极坐标形式
r, theta := cmplx.Polar(z1)
fmt.Printf("z1 的极坐标: r=%.2f, θ=%.2f rad (%.1f°)\n",
r, theta, theta*180/math.Pi)
// 从极坐标创建复数
z3 := cmplx.Rect(r, theta)
fmt.Printf("从极坐标重建: %.1f\n", z3)
// 复数的指数和对数
fmt.Println("\n=== 复数指数和对数 ===")
fmt.Printf("exp(z1) = %.2f\n", cmplx.Exp(z1))
fmt.Printf("log(z1) = %.2f\n", cmplx.Log(z1))
fmt.Printf("log10(z1) = %.2f\n", cmplx.Log10(z1))
// 复数的幂运算
fmt.Printf("z1^2 = %.1f\n", cmplx.Pow(z1, complex(2, 0)))
fmt.Printf("z1^z2 = %.2f\n", cmplx.Pow(z1, z2))
// 复数的三角函数
fmt.Println("\n=== 复数三角函数 ===")
z := complex(1, 1)
fmt.Printf("z = %.1f\n", z)
fmt.Printf("sin(z) = %.2f\n", cmplx.Sin(z))
fmt.Printf("cos(z) = %.2f\n", cmplx.Cos(z))
fmt.Printf("tan(z) = %.2f\n", cmplx.Tan(z))
// 实际应用:电路分析中的阻抗计算
fmt.Println("\n=== 实际应用:电路阻抗 ===")
// 电阻 R = 100Ω
R := complex(100, 0)
// 电感 L = 0.1H, 频率 f = 60Hz
// XL = 2πfL
f := 60.0
L := 0.1
XL := 2 * math.Pi * f * L
inductance := complex(0, XL)
// 电容 C = 10μF
// XC = 1/(2πfC)
C := 10e-6
XC := 1 / (2 * math.Pi * f * C)
capacitance := complex(0, -XC)
// 总阻抗 Z = R + jXL + jXC
totalImpedance := R + inductance + capacitance
fmt.Printf("电阻: %.0fΩ\n", real(R))
fmt.Printf("感抗: %.1fjΩ\n", imag(inductance))
fmt.Printf("容抗: %.1fjΩ\n", imag(capacitance))
fmt.Printf("总阻抗: %.1f Ω\n", totalImpedance)
fmt.Printf("阻抗模长: %.1f Ω\n", cmplx.Abs(totalImpedance))
fmt.Printf("相位角: %.1f°\n", cmplx.Phase(totalImpedance)*180/math.Pi)
}math/rand - 随机数生成
生成各种类型的随机数:
go
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 设置随机种子
rand.Seed(time.Now().UnixNano())
// 基本随机数
fmt.Println("=== 基本随机数 ===")
fmt.Printf("随机整数: %d\n", rand.Int())
fmt.Printf("随机 int32: %d\n", rand.Int31())
fmt.Printf("随机 int64: %d\n", rand.Int63())
fmt.Printf("随机 uint32: %d\n", rand.Uint32())
fmt.Printf("随机 uint64: %d\n", rand.Uint64())
// 范围内的随机数
fmt.Println("\n=== 范围内随机数 ===")
fmt.Printf("0-99 的随机数: %d\n", rand.Intn(100))
fmt.Printf("1-6 的随机数 (骰子): %d\n", rand.Intn(6)+1)
// 浮点随机数
fmt.Println("\n=== 浮点随机数 ===")
fmt.Printf("0.0-1.0 的随机数: %.4f\n", rand.Float32())
fmt.Printf("0.0-1.0 的随机数: %.4f\n", rand.Float64())
// 正态分布随机数
fmt.Println("\n=== 正态分布随机数 ===")
for i := 0; i < 5; i++ {
normal := rand.NormFloat64()
fmt.Printf("标准正态分布: %.4f\n", normal)
}
// 指数分布随机数
fmt.Println("\n=== 指数分布随机数 ===")
for i := 0; i < 5; i++ {
exp := rand.ExpFloat64()
fmt.Printf("指数分布: %.4f\n", exp)
}
// 随机排列
fmt.Println("\n=== 随机排列 ===")
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Printf("原始数组: %v\n", numbers)
// 洗牌算法
rand.Shuffle(len(numbers), func(i, j int) {
numbers[i], numbers[j] = numbers[j], numbers[i]
})
fmt.Printf("洗牌后: %v\n", numbers)
// 随机选择
fmt.Println("\n=== 随机选择 ===")
fruits := []string{"苹果", "香蕉", "橙子", "葡萄", "草莓"}
randomFruit := fruits[rand.Intn(len(fruits))]
fmt.Printf("随机水果: %s\n", randomFruit)
// 加权随机选择
fmt.Println("\n=== 加权随机选择 ===")
items := []string{"普通", "稀有", "史诗", "传说"}
weights := []int{50, 30, 15, 5} // 权重
// 计算累积权重
totalWeight := 0
for _, weight := range weights {
totalWeight += weight
}
// 随机选择
randomValue := rand.Intn(totalWeight)
currentWeight := 0
selectedItem := ""
for i, weight := range weights {
currentWeight += weight
if randomValue < currentWeight {
selectedItem = items[i]
break
}
}
fmt.Printf("加权随机选择: %s (权重: %v)\n", selectedItem, weights)
// 创建自定义随机数生成器
fmt.Println("\n=== 自定义随机数生成器 ===")
source := rand.NewSource(12345) // 固定种子
customRand := rand.New(source)
fmt.Println("使用固定种子的随机数序列:")
for i := 0; i < 5; i++ {
fmt.Printf(" %d\n", customRand.Intn(100))
}
}math/bits - 位操作
高效的位级操作函数:
go
package main
import (
"fmt"
"math/bits"
)
func main() {
x := uint64(0b11010110) // 214 in decimal
fmt.Printf("x = %d (二进制: %08b)\n", x, x)
// 位计数
fmt.Println("\n=== 位计数 ===")
fmt.Printf("前导零个数: %d\n", bits.LeadingZeros64(x))
fmt.Printf("尾随零个数: %d\n", bits.TrailingZeros64(x))
fmt.Printf("1的个数: %d\n", bits.OnesCount64(x))
// 位长度
fmt.Printf("位长度: %d\n", bits.Len64(x))
// 位反转
fmt.Println("\n=== 位操作 ===")
reversed := bits.Reverse64(x)
fmt.Printf("位反转: %064b\n", reversed)
// 字节反转
byteReversed := bits.ReverseBytes64(x)
fmt.Printf("字节反转: %d (二进制: %064b)\n", byteReversed, byteReversed)
// 循环左移和右移
fmt.Println("\n=== 循环移位 ===")
leftRotated := bits.RotateLeft64(x, 2)
rightRotated := bits.RotateLeft64(x, -2) // 等价于右移2位
fmt.Printf("原值: %08b\n", x)
fmt.Printf("左移2位: %08b (%d)\n", leftRotated, leftRotated)
fmt.Printf("右移2位: %08b (%d)\n", rightRotated, rightRotated)
// 加法和乘法的进位检测
fmt.Println("\n=== 进位检测 ===")
a, b := uint64(0xFFFFFFFFFFFFFFFF), uint64(1)
sum, carry := bits.Add64(a, b, 0)
fmt.Printf("%d + %d = %d, 进位: %d\n", a, b, sum, carry)
// 乘法
high, low := bits.Mul64(0xFFFFFFFF, 0xFFFFFFFF)
fmt.Printf("0xFFFFFFFF × 0xFFFFFFFF = 0x%X%016X\n", high, low)
// 除法
quo, rem := bits.Div64(high, low, 0xFFFFFFFF)
fmt.Printf("除法结果: 商=%d, 余数=%d\n", quo, rem)
// 实际应用:快速幂运算
fmt.Println("\n=== 实际应用:快速幂运算 ===")
fastPow := func(base, exp uint64) uint64 {
result := uint64(1)
for exp > 0 {
if exp&1 == 1 {
result *= base
}
base *= base
exp >>= 1
}
return result
}
base, exp := uint64(2), uint64(10)
result := fastPow(base, exp)
fmt.Printf("%d^%d = %d\n", base, exp, result)
// 位操作优化的算法
fmt.Println("\n=== 位操作算法 ===")
// 检查是否为2的幂
isPowerOfTwo := func(n uint64) bool {
return n > 0 && (n&(n-1)) == 0
}
testNumbers := []uint64{1, 2, 3, 4, 8, 15, 16, 32}
for _, num := range testNumbers {
fmt.Printf("%d 是2的幂: %v\n", num, isPowerOfTwo(num))
}
// 计算下一个2的幂
nextPowerOfTwo := func(n uint64) uint64 {
if n == 0 {
return 1
}
return 1 << bits.Len64(n-1)
}
fmt.Println("\n下一个2的幂:")
for _, num := range []uint64{5, 7, 9, 15, 17} {
next := nextPowerOfTwo(num)
fmt.Printf("%d -> %d\n", num, next)
}
}9. 实际应用场景
科学计算示例
使用 math 包进行科学计算:
go
package main
import (
"fmt"
"math"
)
// 物理常量
const (
SpeedOfLight = 299792458.0 // 光速 (m/s)
Gravity = 9.80665 // 重力加速度 (m/s²)
PlanckConst = 6.62607015e-34 // 普朗克常数 (J⋅s)
)
// 计算自由落体运动
func freeFall(height, time float64) (position, velocity float64) {
// s = h - (1/2)gt²
position = height - 0.5*Gravity*math.Pow(time, 2)
// v = gt
velocity = Gravity * time
return
}
// 计算抛物线运动
func projectileMotion(v0, angle, t float64) (x, y, vx, vy float64) {
angleRad := angle * math.Pi / 180
// 水平位移和速度
x = v0 * math.Cos(angleRad) * t
vx = v0 * math.Cos(angleRad)
// 垂直位移和速度
y = v0*math.Sin(angleRad)*t - 0.5*Gravity*math.Pow(t, 2)
vy = v0*math.Sin(angleRad) - Gravity*t
return
}
// 计算复利
func compoundInterest(principal, rate float64, years int, compoundingFreq int) float64 {
// A = P(1 + r/n)^(nt)
return principal * math.Pow(1+rate/float64(compoundingFreq), float64(compoundingFreq*years))
}
func main() {
fmt.Println("=== 物理计算示例 ===")
// 自由落体
height := 100.0 // 米
time := 3.0 // 秒
pos, vel := freeFall(height, time)
fmt.Printf("从%.0f米高度自由落体%.0f秒后:\n", height, time)
fmt.Printf(" 位置: %.2f米\n", pos)
fmt.Printf(" 速度: %.2f米/秒\n", vel)
// 抛物线运动
fmt.Println("\n抛物线运动:")
v0 := 50.0 // 初始速度 m/s
angle := 45.0 // 发射角度
t := 2.0 // 时间
x, y, vx, vy := projectileMotion(v0, angle, t)
fmt.Printf("初速度%.0f m/s,角度%.0f°,%.0f秒后:\n", v0, angle, t)
fmt.Printf(" 水平位置: %.2f米\n", x)
fmt.Printf(" 垂直位置: %.2f米\n", y)
fmt.Printf(" 水平速度: %.2f m/s\n", vx)
fmt.Printf(" 垂直速度: %.2f m/s\n", vy)
fmt.Println("\n=== 金融计算示例 ===")
// 复利计算
principal := 10000.0 // 本金
rate := 0.05 // 年利率 5%
years := 10 // 年数
freq := 12 // 每年复利12次(月复利)
amount := compoundInterest(principal, rate, years, freq)
fmt.Printf("本金: $%.2f\n", principal)
fmt.Printf("年利率: %.1f%%\n", rate*100)
fmt.Printf("投资期: %d年\n", years)
fmt.Printf("复利频率: 每年%d次\n", freq)
fmt.Printf("最终金额: $%.2f\n", amount)
fmt.Printf("收益: $%.2f\n", amount-principal)
// 贷款月供计算
fmt.Println("\n贷款月供计算:")
loanAmount := 300000.0 // 贷款金额
annualRate := 0.04 // 年利率 4%
loanYears := 30 // 贷款年限
monthlyRate := annualRate / 12
numPayments := float64(loanYears * 12)
// 月供公式: M = P * [r(1+r)^n] / [(1+r)^n - 1]
monthlyPayment := loanAmount * (monthlyRate * math.Pow(1+monthlyRate, numPayments)) /
(math.Pow(1+monthlyRate, numPayments) - 1)
totalPayment := monthlyPayment * numPayments
totalInterest := totalPayment - loanAmount
fmt.Printf("贷款金额: $%.2f\n", loanAmount)
fmt.Printf("年利率: %.1f%%\n", annualRate*100)
fmt.Printf("贷款期限: %d年\n", loanYears)
fmt.Printf("月供: $%.2f\n", monthlyPayment)
fmt.Printf("总还款: $%.2f\n", totalPayment)
fmt.Printf("总利息: $%.2f\n", totalInterest)
}数据分析工具
创建简单的统计分析工具:
go
package main
import (
"fmt"
"math"
"sort"
)
// Statistics 统计数据结构
type Statistics struct {
Data []float64
}
// NewStatistics 创建新的统计对象
func NewStatistics(data []float64) *Statistics {
// 复制数据以避免修改原始切片
dataCopy := make([]float64, len(data))
copy(dataCopy, data)
return &Statistics{Data: dataCopy}
}
// Mean 计算平均值
func (s *Statistics) Mean() float64 {
if len(s.Data) == 0 {
return 0
}
sum := 0.0
for _, value := range s.Data {
sum += value
}
return sum / float64(len(s.Data))
}
// Median 计算中位数
func (s *Statistics) Median() float64 {
if len(s.Data) == 0 {
return 0
}
sorted := make([]float64, len(s.Data))
copy(sorted, s.Data)
sort.Float64s(sorted)
n := len(sorted)
if n%2 == 0 {
return (sorted[n/2-1] + sorted[n/2]) / 2
}
return sorted[n/2]
}
// Mode 计算众数
func (s *Statistics) Mode() []float64 {
if len(s.Data) == 0 {
return nil
}
frequency := make(map[float64]int)
for _, value := range s.Data {
frequency[value]++
}
maxFreq := 0
for _, freq := range frequency {
if freq > maxFreq {
maxFreq = freq
}
}
var modes []float64
for value, freq := range frequency {
if freq == maxFreq {
modes = append(modes, value)
}
}
sort.Float64s(modes)
return modes
}
// Variance 计算方差
func (s *Statistics) Variance() float64 {
if len(s.Data) <= 1 {
return 0
}
mean := s.Mean()
sumSquaredDiff := 0.0
for _, value := range s.Data {
diff := value - mean
sumSquaredDiff += diff * diff
}
return sumSquaredDiff / float64(len(s.Data)-1) // 样本方差
}
// StandardDeviation 计算标准差
func (s *Statistics) StandardDeviation() float64 {
return math.Sqrt(s.Variance())
}
// Range 计算极差
func (s *Statistics) Range() (min, max, rangeVal float64) {
if len(s.Data) == 0 {
return 0, 0, 0
}
min = s.Data[0]
max = s.Data[0]
for _, value := range s.Data {
if value < min {
min = value
}
if value > max {
max = value
}
}
rangeVal = max - min
return
}
// Percentile 计算百分位数
func (s *Statistics) Percentile(p float64) float64 {
if len(s.Data) == 0 || p < 0 || p > 100 {
return 0
}
sorted := make([]float64, len(s.Data))
copy(sorted, s.Data)
sort.Float64s(sorted)
if p == 100 {
return sorted[len(sorted)-1]
}
index := p / 100 * float64(len(sorted)-1)
lower := int(math.Floor(index))
upper := int(math.Ceil(index))
if lower == upper {
return sorted[lower]
}
weight := index - float64(lower)
return sorted[lower]*(1-weight) + sorted[upper]*weight
}
// ZScore 计算Z分数
func (s *Statistics) ZScore(value float64) float64 {
mean := s.Mean()
std := s.StandardDeviation()
if std == 0 {
return 0
}
return (value - mean) / std
}
func main() {
// 示例数据:学生考试成绩
scores := []float64{85, 92, 78, 96, 85, 88, 76, 89, 92, 84, 90, 87, 83, 91, 79}
stats := NewStatistics(scores)
fmt.Println("=== 学生成绩统计分析 ===")
fmt.Printf("原始数据: %v\n", scores)
fmt.Printf("数据量: %d\n", len(scores))
fmt.Println("\n=== 集中趋势 ===")
fmt.Printf("平均分: %.2f\n", stats.Mean())
fmt.Printf("中位数: %.2f\n", stats.Median())
fmt.Printf("众数: %v\n", stats.Mode())
fmt.Println("\n=== 离散程度 ===")
min, max, rangeVal := stats.Range()
fmt.Printf("最低分: %.2f\n", min)
fmt.Printf("最高分: %.2f\n", max)
fmt.Printf("极差: %.2f\n", rangeVal)
fmt.Printf("方差: %.2f\n", stats.Variance())
fmt.Printf("标准差: %.2f\n", stats.StandardDeviation())
fmt.Println("\n=== 百分位数 ===")
percentiles := []float64{25, 50, 75, 90, 95}
for _, p := range percentiles {
value := stats.Percentile(p)
fmt.Printf("第%.0f百分位数: %.2f\n", p, value)
}
fmt.Println("\n=== Z分数分析 ===")
testScores := []float64{95, 85, 75}
for _, score := range testScores {
z := stats.ZScore(score)
fmt.Printf("成绩%.0f的Z分数: %.2f", score, z)
if math.Abs(z) > 2 {
fmt.Printf(" (异常值)")
}
fmt.Println()
}
// 正态分布检验(简化版)
fmt.Println("\n=== 分布特征 ===")
mean := stats.Mean()
std := stats.StandardDeviation()
// 计算偏度(简化)
sumCubedDiff := 0.0
for _, value := range scores {
diff := (value - mean) / std
sumCubedDiff += diff * diff * diff
}
skewness := sumCubedDiff / float64(len(scores))
fmt.Printf("偏度: %.3f", skewness)
if math.Abs(skewness) < 0.5 {
fmt.Printf(" (近似对称)")
} else if skewness > 0 {
fmt.Printf(" (右偏)")
} else {
fmt.Printf(" (左偏)")
}
fmt.Println()
// 成绩等级分布
fmt.Println("\n=== 成绩等级分布 ===")
grades := map[string]int{"A": 0, "B": 0, "C": 0, "D": 0, "F": 0}
for _, score := range scores {
switch {
case score >= 90:
grades["A"]++
case score >= 80:
grades["B"]++
case score >= 70:
grades["C"]++
case score >= 60:
grades["D"]++
default:
grades["F"]++
}
}
for grade, count := range grades {
percentage := float64(count) / float64(len(scores)) * 100
fmt.Printf("%s等级: %d人 (%.1f%%)\n", grade, count, percentage)
}
}10. 最佳实践
1. 精度和性能考虑
- 了解浮点数的精度限制,避免直接比较浮点数
- 对于高精度计算,使用
math/big包 - 在性能敏感的场景中,考虑使用位操作优化
2. 错误处理
- 检查除零错误和定义域错误
- 处理 NaN 和无穷大值
- 验证输入参数的有效性
3. 数值稳定性
- 避免大数减小数导致的精度损失
- 使用数值稳定的算法实现
- 注意累积误差的影响
4. 代码可读性
- 使用有意义的常量名
- 添加适当的注释说明数学公式
- 将复杂的数学计算封装成函数
11. 总结
Go 的 math 包及其子包提供了全面的数学计算能力,主要特点包括:
- 功能完整: 涵盖基础数学运算到高级数学函数
- 高精度支持:
math/big提供任意精度运算 - 复数支持:
math/cmplx提供完整的复数运算 - 随机数生成:
math/rand提供多种分布的随机数 - 位操作优化:
math/bits提供高效的位级操作
通过合理使用这些包,可以满足从简单计算到复杂科学计算的各种需求,是 Go 语言进行数值计算的强大工具集。