<p>math.Abs(a - b) 返回 a 与 b 差值的绝对值,用于计算两数间的非负距离。</p>

用 math.Abs(a - b) 判断浮点数是否相等
Go 没有内置的浮点数“相等”语义,== 直接比较会因精度丢失导致意外结果。比如 0.1 + 0.2 == 0.3 返回 false,这是 IEEE 754 表示限制,不是 Go 的 bug。
正确做法是引入一个极小容差值 epsilon,判断两数之差的绝对值是否小于它:
import "math"
<p>a, b := 0.1+0.2, 0.3
epsilon := 1e-9
if math.Abs(a-b) < epsilon {
// 视为相等
}-
epsilon不是固定值:科学计算常用1e-15(float64机器精度量级),业务逻辑常取1e-6~1e-9,取决于你数据的量级和误差容忍度 - 别用
1e-16或更小:可能比实际计算误差还小,反而失效 - 避免对数量级差异大的数直接比差值:比如比较
1e10和1e10+1,1的绝对差看似小,但相对误差已达1e-10;此时应考虑相对误差或归一化
用 math.IsNaN 和 math.IsInf 排除非法值再比较
如果参与比较的浮点数可能来自用户输入、网络或计算中间结果,a 或 b 可能是 NaN 或无穷大——这时 math.Abs(a - b) 会返回 NaN,整个条件恒为 false,且不报错,极易漏判。
- 必须先检查:
!math.IsNaN(a) && !math.IsNaN(b) && !math.IsInf(a, 0) && !math.IsInf(b, 0) - 注意
math.IsInf(x, 0)同时捕获正负无穷;若只关心正无穷,用math.IsInf(x, +1) - 常见坑:调用
math.Sqrt(-1)、0.0 / 0.0、1.0 / 0.0等未加防护就进比较逻辑
用 strconv.ParseFloat 读字符串时注意精度截断
从 JSON、配置文件或表单拿到的数字字符串,经 strconv.ParseFloat(s, 64) 转成 float64 后,可能已丢失原始精度。比如字符串 "0.10000000000000000555" 解析后和 0.1 在内存中几乎一样,但若你期望“精确到小数点后 10 位”,这种隐式截断会导致后续比较失准。
立即学习“go语言免费学习笔记(深入)”;
- 如果业务要求高保真(如金融、ID、哈希校验),别用
float64存,改用string或int64(单位转为微秒/厘/最小货币单位) - 若必须解析,确认源字符串本身没多余有效位;可用正则粗筛:
^\d+(\.\d{1,15})?$(float64通常可靠小数点后 15 位) -
json.Unmarshal默认走ParseFloat,同理需警惕
第三方库如 github.com/yourbasic/float 提供开箱即用的比较工具
重复写 math.Abs + epsilon + IsNaN 检查容易遗漏,尤其在多个包里分散使用时。轻量库如 yourbasic/float 封装了 Equal、EqualAbs、EqualRel 等函数,内部已处理边界情况。
- 示例:
float.Equal(a, b, 1e-9)自动跳过NaN和Inf - 不建议为简单场景引入重量级数学库(如
gonum),但yourbasic/float仅一个文件,无依赖,适合嵌入 - 注意它默认用绝对误差;相对误差要显式调
float.EqualRel(a, b, 1e-6)
浮点比较真正的复杂点不在代码怎么写,而在于你得想清楚:这个“相等”在你的业务里到底意味着什么——是测量误差容忍?还是算法收敛阈值?还是 UI 展示四舍五入后的视觉一致?选错 epsilon 或混用绝对/相对判断,比写错一行代码更难调试。










