Go语言提供了两种浮点数类型:float32和float64,分别对应IEEE-754标准的单精度和双精度浮点数。
1. 浮点数类型概述
1.1. float32 (单精度浮点数)
1. 占用32位即4字节的存储空间;
2. 大约提供6-7位十进制精度;
3. 范围约为 ±1.18e-38 到 ±3.4e38;
1.2. float64 (双精度浮点数)
1. 占用64位即8字节存储空间;
2. 大约提供15-16位十进制精度;
3. 范围约为 ±2.23e-308 到 ±1.8e308;
2. 浮点数声明与初始化
var f1 float32 = 3.14
var f2 float64 = 3.141592653589793
// 简写形式(默认为float64)
f3 := 3.14 // float64
3. 浮点数精度问题
由于浮点数的二进制表示特性,某些十进制小数无法精确表示:
func main() {
f := 0.1
sum := f + f + f
fmt.Println(sum) // 输出: 0.30000000000000004
}
如果要解决浮点数运算的精度问题,可以使用第三方的包 decimal 。
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
// 加法
var num1 float64 = 3.1
var num2 float64 = 4.2
num3 := decimal.NewFromFloat(num1).Add(decimal.NewFromFloat(num2))
fmt.Println(num3)
// 减去
m1 := 8.2
m2 := 3.8
m3 := decimal.NewFromFloat(m1).Sub(decimal.NewFromFloat(m2))
fmt.Println(m3)
}
4. 特殊浮点数值
Go浮点数支持IEEE-754定义的特殊值:
1. 正无穷大(+Inf)和负无穷大(-Inf)
2. 非数(NaN, Not a Number)
func main() {
posInf := math.Inf(1) // 正无穷
negInf := math.Inf(-1) // 负无穷
nan := math.NaN() // 非数
fmt.Println(posInf, negInf, nan)
}
5. 浮点数比较
由于精度问题,直接比较浮点数可能不可靠:
// 不推荐的比较方式
if a == b { ... }
// 推荐的比较方式(使用允许的误差范围)
const epsilon = 1e-9
if math.Abs(a-b) < epsilon { ... }
对于NaN的比较:
if math.IsNaN(x) { ... }
6. 数学运算
Go的math包提供了丰富的浮点数运算函数:
func main() {
a := 2.0
b := 3.0
fmt.Println(math.Sqrt(a)) // 平方根
fmt.Println(math.Pow(a, b)) // 幂运算
fmt.Println(math.Sin(a)) // 正弦
fmt.Println(math.Log(a)) // 自然对数
fmt.Println(math.Floor(a)) // 向下取整
fmt.Println(math.Ceil(a)) // 向上取整
fmt.Println(math.Mod(a, b)) // 取模
}
7. 类型转换
func main() {
var f32 float32 = 1.5
var f64 float64 = 2.7
// float32转float64
f64 = float64(f32)
// float64转float32(可能丢失精度)
f32 = float32(f64)
// 整数转浮点数
i := 10
f32 = float32(i)
f64 = float64(i)
}
8. 格式化输出
func main() {
f := 123.456
fmt.Printf("%f\n", f) // 默认格式: 123.456000
fmt.Printf("%.2f\n", f) // 保留两位小数: 123.46
fmt.Printf("%e\n", f) // 科学计数法: 1.234560e+02
fmt.Printf("%g\n", f) // 根据情况选择%f或%e: 123.456
}
9. 最佳实践
1. 在大多数情况下,优先使用float64以获得更高的精度;
2. 避免直接比较浮点数,应使用允许的误差范围;
3. 注意浮点数的精度限制,特别是涉及金钱计算时;
4. 对于需要精确十进制计算的场景,考虑使用math/big包;
10. 性能考虑
1. float32占用更少内存,适合大量数据存储;
2. float64提供更高精度,是Go中默认的浮点类型;
3. 在现代CPU上,float32和float64的运算性能差异通常不大;
通过理解Go语言中浮点数的这些特性和行为,可以避免常见的精度问题,并编写出更可靠的数值计算代码。