Go 中高精度浮点数与定点数的比较

Go 中高精度浮点数与定点数的比较

Go 语言中处理高精度浮点数/定点数(通常使用标准库的 math/big 包中的 big.Float / big.Rat,或者业界常用的三方库 shopspring/decimal)时,同样存在数值与精度的比较逻辑。

1. 业界常用库:shopspring/decimal(金融/电商标准)

Go 业务开发中处理金额最常用的是 [github.com/shopspring/decimal](https://github.com/shopspring/decimal),其行为与 Java 的区别最为类似:

package main

import (
	"fmt"
	"github.com/shopspring/decimal"
)

func main() {
	a, _ := decimal.NewFromString("2.0")
	b, _ := decimal.NewFromString("2.00")

	// 1. Equal():仅比较数值大小(等价于 Java 的 compareTo == 0)
	fmt.Println(a.Equal(b)) // true

	// 2. Cmp():返回 -1, 0, 1(完全等价于 Java 的 compareTo)
	fmt.Println(a.Cmp(b))   // 0

	// 3. Go 原生 == / reflect.DeepEqual:比较底层结构,不代表数值相等
	// decimal.Decimal 的内部表示包含数值与 exp 指数等信息
	// a.exp = -1, b.exp = -2
	fmt.Println(a == b)     // false(等价于 Java 的 equals 陷阱)
}

  • 数值判断:始终使用 a.Equal(b)a.Cmp(b) == 0
  • 避免直接 ==:不要用 a == b 或将 decimal.Decimal 直接作为 Go map 的 key 进行数值比对,因为结构体内部存储的指数(exponent)不同会导致 == 判定为 false

2. 标准库:math/big.Float

如果使用 Go 原生标准库 math/big

package main

import (
	"fmt"
	"math/big"
)

func main() {
	a, _, _ := big.ParseFloat("2.0", 10, 64, big.ToNearestEven)
	b, _, _ := big.ParseFloat("2.00", 10, 64, big.ToNearestEven)

	// 1. Cmp():比较数值大小
	// a < b 返回 -1,a == b 返回 0,a > b 返回 1
	fmt.Println(a.Cmp(b)) // 0

	// 2. big.Float 没有内置类似 equals 的直接方法
	// 它的结构包含 prec(精度)、mode(舍入模式)和 mant(尾数切片)
	// 并且指针类型不能直接通过 == 比较底层值
}


核心对比总结

场景 Go(shopspring/decimal Java(BigDecimal 行为特性
仅比较数值 a.Equal(b)a.Cmp(b) == 0 a.compareTo(b) == 0 推荐:2.02.00 视为相等
比较数值 + 精度/底层结构 a == b a.equals(b) 陷阱:2.02.00 视为不相等
Map/Hash Key 行为 m[a]m[b] 会被视作不同 key HashMap 中被视作不同 key 需先规范化(如统一保留指定小数位)再作为 key

posted on 2026-09-05 00:17  HeJIW  阅读(5)  评论(0)    收藏  举报

导航