最稳解法是strconv.FormatFloat(x, 'f', -1, 64),它实现无科学计数法、最小必要小数位、自动去尾零;若需“最多N位小数”,须先math.Round(x*10^N)/10^N预处理再调用该函数。

导出浮点数时精度失控,根本原因不是格式化函数写错了,而是你没区分“展示精度”“存储精度”和“计算精度”这三类需求——选错路径,后面所有 fmt 或 strconv 调用都只是在掩盖问题。
strconv.FormatFloat 的 'f' 和 -1 精度怎么配才不翻车
绝大多数导出场景(如经纬度、传感器读数)要的是「无科学计数法 + 最小必要小数位」,strconv.FormatFloat(x, 'f', -1, 64) 是最直接解法。它不会补零,也不会四舍五入,只保留 float64 能精确表达的最小位数。
- 传
'g'动词 → 可能输出"1.23e+07",JSON 或 CSV 解析器直接报错 - 传
'f'但精度为正整数(如2)→ 强制截断或补零,0.001变成"0.00",丢数据 - bitSize 不填
64→float64值传进去却填32,直接 panic - 负数也适用,
strconv.FormatFloat(-3.14159, 'f', -1, 64)输出"-3.14159",符号位自动处理
需要“最多 N 位小数且去尾零”就得先 round 再 format
比如导出金额字段要求「最多 2 位小数,0.1000 → "0.1",0.105 → "0.11"」,strconv.FormatFloat 本身不四舍五入,必须手动预处理:
- 用
math.Round(x * math.Pow10(n)) / math.Pow10(n)先缩放再还原,n=2 就是两位小数 - round 后仍用
'f'+-1:避免0.1变成"0.10000000000000001" - 别用
fmt.Sprintf("%.2f", x)→ 它对0.001输出"0.00",不是“最多”,是“强制” - 注意
math.Round在 Go 1.22+ 才支持 float64;旧版本用math.Floor(x+0.5)要自己处理负数
写入文件时 fmt.Fprintf 直接格式化的坑
想省一步直接 fmt.Fprintf(file, "%.6f", x)?小心这些静默错误:
立即学习“go语言免费学习笔记(深入)”;
-
%.6f对12345678.0输出"12345678.000000",占位超长,CSV 列错位 -
%.6g对0.0000001输出"1e-07",下游系统不认 - 文件句柄没检查 err →
file是 nil,fmt.Fprintfpanic 报invalid memory address - 忘了
defer file.Close()→ 缓冲区未刷盘,小文件内容为空 - 并发写同一文件 → 不加锁,内容乱序,
lat:34.05和lon:-118.24可能被拆成两行
真正难的不是怎么写,而是要不要用 float64
如果你导出的是金额、金融利率、高精度传感器原始值,float64 从输入那一刻就失真了。这时候:
- 金额改用整数单位(分、厘)存储,导出前用
strconv.Itoa+ 手动插小数点,100% 精确 - 必须用十进制小数 → 上
shopspring/decimal,调d.String(),不碰strconv和fmt - 导出 JSON 时别自己拼字符串:
json.Marshal(map[string]decimal.Decimal{...})配自定义MarshalJSON方法 - Excel 导出用
excelize的SetCellValue直接传float64→ 它内部会做类型判断,比你手格式化更稳


















