为了账号安全,请及时绑定邮箱和手机立即绑定

Go - 货币计算

Go - 货币计算

冉冉说 2021-11-29 19:29:00
我正在尝试用 Go 进行货币计算。环顾标准库,big/math似乎是我可以利用的。我运行了一些代码来检查它是如何工作的。首先我用 Float.SetFloat64()var f = 18.9var f2 = 1.65bf := new(big.Float)bf.Add(bf, new(big.Float).SetFloat64(f))bf.Add(bf, new(big.Float).SetFloat64(f2))result, _ := bf.Float64()fmt.Println(result)这给了我结果:20.549999999999997就像用float64类型计算一样。既然我在和钱打交道,结果一定是20.55。相反,当使用 Float.SetString()var s = fmt.Sprintf("%f", 18.9)var s2 = fmt.Sprintf("%f", 1.65)bf := new(big.Float)bf2, _ := new(big.Float).SetString(s)bf3, _ := new(big.Float).SetString(s2)bf.Add(bf, bf2)bf.Add(bf, bf3)result, _ := bf.Float64()fmt.Println(result)这给了我结果:20.55似乎我可以将它用于我的目的(但我不确定..)。我的问题是为什么使用Float.SetFloat64()和 之间有区别Float.SetString()?Float.SetString()用于货币计算时是否有任何陷阱?提前致谢,请原谅我的英语。[编辑]我知道应该避免使用浮点类型来表示货币价值。但类型的选择并不在我的控制之下..我想知道以上两个问题中的一个(或两个)的答案。或者为什么Float.SetString()给我看似正确的结果的原因也很有帮助。
查看完整描述

3 回答

?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

永远,永远,永远不要使用浮动货币。它是一种不精确的类型,因此您最终不得不四舍五入计算并且最终在这里和那里损失(或获得)一分钱。您可能认为这没问题,但您的会计师会告诉您不是。你必须完全准确。

因此,要么使用专门的任意精度十进制类型,要么使用整数并保存一分钱(或一分钱的分数)并适当地显示它。(就像您如何将日期保存为自 1970 年以来的秒数,但将它们显示为 dd-mm-yyyy)。

附注。切勿使用浮动货币。真的。

聚苯乙烯。不要使用浮动货币,永远不要永远。


查看完整回答
反对 回复 2021-11-29
?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

使用big.Int代表 1000ths 或 10000ths 一分的值。浮点值不适用于货币,尤其是在交易时。如果有人要求您使用浮点值,请尝试说服他们这是一个坏主意。如果那不起作用,请重新考虑您与他们合作的决定。考虑到您可能会无意中卷入非法活动:https : //en.wikipedia.org/wiki/Salami_slicing

回答您的技术问题:

big.Float值不是像big.Int值那样的任意精度。

SetFloat64将浮点数的精度设置为一段float64时间的精度,SetString根据字符串的内容进行设置。

无论哪种方式,您都希望对 big.Float 值设置的精度进行深思熟虑。您可以使用https://golang.org/pkg/math/big/#Float.SetPrec控制它SetPrec

编辑:

至于陷阱,请考虑基数 10 中的 0.10 在基数 2 中没有有限表示。由于big.Float没有base字段或与之对应的任何内容,因此它实际上无法准确存储 0.10。

基本上,只要您使用 Float 作为浮点数而不是整数,您就会留下确切的值。


查看完整回答
反对 回复 2021-11-29
?
暮色呼如

TA贡献1853条经验 获得超9个赞

您可以使用实现“无限精度”十进制算术的gopkg.in/inf.v0。


对于上面指定的金额,这里是一个例子:


func main() {

    var amt inf.Dec

    amt.SetUnscaled(1890)

    amt.SetScale(2)

    fmt.Println(amt.String())

    var amt1 inf.Dec

    amt1.SetUnscaled(165)

    amt1.SetScale(2)

    fmt.Println(amt1.String())

    var total = inf.NewDec(5, 2)

    total = total.Add(&amt, &amt1)

    fmt.Println(total.String())

}

它应该按预期打印出 20.55。


查看完整回答
反对 回复 2021-11-29
  • 3 回答
  • 0 关注
  • 333 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信