go 解决货币计算的难题:避免浮点数陷阱

在开发的初始阶段,我们经常会遇到"浮点数精度"和"货币值表示"的问题。

那么,如何处理货币,如何存储和传递它们。

为什么是问题?

Go语言中的标准浮点类型具有一定的精度(像其他任何语言一样),你不能在货币操作中使用它们。这里有一个最简单的例子:

go 复制代码
var v1, v2 = 0.1, 0.2
fmt.Println(v1 + v2)
// 输出:0.30000000000000004

你可以计算你需要将一个值与另一个值相加多少次,才能在你的账户上获得额外的钱!但反过来也是一样 --- 在这种情况下,你只是失去了你的钱。

这不仅在对你的钱进行数学运算时有问题,而且在不同系统或服务之间传递数据时也是有问题的。

下一个问题 --- 传递你的钱

每次将你的钱从/到浮点数进行编组时,都会遇到与上述相同的问题,以及与编组器实现有关的其他问题 - json,xml,text等等...

另一个问题是四舍五入。如果你处理的是货币,你总会面临四舍五入的问题。你应该如何四舍五入你的货币值?例如 0.345 元,一般我们还是会四舍五入到 0.35 元?

我们的选择是什么?

有一些特殊的类型可用于货币的表示和计算。

Go标准库有 big.Float 类型(来自 math/big 包,表示任意精度的浮点数)。与 float32 和 float64 不同,它们具有固定的大小和精度,big.Float 允许你为数字和计算设置任意精度。

另一个不错的选择是 decimal 库 github.com/shopspring/...

关于四舍五入:

  • 1.234 => 1.23
  • 1.235 => 1.24
  • 1.236 => 1.24

例如,shopspring/decimal 提供了适当舍入值的方法。

考虑的另一个好选择是使用货币单位。这样,你就从浮点数问题转移到整数,并将一切都作为整数计算。在这里唯一使用四舍五入的地方:传递结果值。

现在让我们讨论一下在传递货币时的选择。

  • 使用货币单位 --- 我们将所有内容都传递为整数,这里没有浮点问题。只需控制值的限制,就可以了。
  • 将浮点数作为字符串传递。通常也是一个不错的选择 --- 当你将浮点数作为字符串传递时,带有所需精度(特定小数位数)的字符串,当对方读取此字符串值并将其转换回浮点数时,你就是安全的。

简单的例子

你可以在 Go Playground 上尝试一下。

go 复制代码
package main

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

func main() {
    a := 0.1
    b := 0.2
    c := decimal.NewFromFloat(a)
    d := decimal.NewFromFloat(b)
    fmt.Println(a, b, c.String(), d.String()) 
    fmt.Println(a + b) 
    fmt.Println(c.Add(d).String()) 
}

输出为:

go 复制代码
0.1 0.2 0.1 0.2
0.30000000000000004
0.3

结论

处理货币时 --- 使用 math/big 或一些与货币相关的库,比如 shopspring/decimal,或者只是使用货币单位,在这里不要使用浮点数。将货币作为字符串传递,或者在货币单位中传递,不要在这里使用浮点数。

相关推荐
学步_技术2 分钟前
Python编码系列—Python抽象工厂模式:构建复杂对象家族的蓝图
开发语言·python·抽象工厂模式
wn53126 分钟前
【Go - 类型断言】
服务器·开发语言·后端·golang
Hello-Mr.Wang38 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
救救孩子把41 分钟前
Java基础之IO流
java·开发语言
WG_1742 分钟前
C++多态
开发语言·c++·面试
宇卿.1 小时前
Java键盘输入语句
java·开发语言
希冀1231 小时前
【操作系统】1.2操作系统的发展与分类
后端
Amo Xiang1 小时前
2024 Python3.10 系统入门+进阶(十五):文件及目录操作
开发语言·python
friklogff1 小时前
【C#生态园】提升C#开发效率:深入了解自然语言处理库与工具
开发语言·c#·区块链
GoppViper1 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理