去 - 货币计算

时间:2015-12-28 04:23:28

标签: go

我正在尝试用Go进行货币计算。

环顾标准库,big/math似乎是我可以使用的。{ 我运行了一些代码来检查它是如何工作的。

首先我使用Float.SetFloat64()

var f = 18.9
var f2 = 1.65
bf := 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
它SEEMs我可以用它来达到我的目的(但我不确定......)。

我的问题是

  1. 为什么使用Float.SetFloat64()Float.SetString()之间存在差异?

  2. 使用Float.SetString()进行货币计算时是否存在任何陷阱?

  3. 提前致谢,原谅我的英语。

    [编辑]

    我知道应该避免使用浮动类型代表货币价值 但是这种类型的选择并不是我真正掌控的。

    我想知道上述两个问题中任何一个(或两个)的答案。

    或者Float.SetString()给我看似正确的结果的原因也很有帮助。

2 个答案:

答案 0 :(得分:6)

从来没有,永远不要使用浮动货币。它是一种不精确的类型,所以你最终不得不进行计算,你最终会在这里和那里失去(或获得)一分钱。您可能认为没问题,但您的会计师可以告诉您不是。你 完全准确。

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

PS。切勿使用花车作为货币。真。

PPS。不要使用花车作为货币,永远不要用。

答案 1 :(得分:2)

使用代表1000分或10000分的big.Int值。浮点值不适合金钱,特别是在交易时。如果有人要求你使用浮点值,试着说服他们这是一个坏主意。如果这不起作用,请重新考虑您与他们合作的决定。考虑到您可能无意中涉及非法的事情:https://en.wikipedia.org/wiki/Salami_slicing

回答您的技术问题:

big.Float值不是big.Int值之类的任意精度。

SetFloat64将float的精度设置为float64的精度,而SetString则根据字符串的内容设置它。

无论哪种方式,您都希望非常谨慎地考虑在big.Float值上设置的精度。您可以使用SetPrec https://golang.org/pkg/math/big/#Float.SetPrec

来控制此问题

修改

至于陷阱,请考虑基数10中的0.10在基数2中没有有限的表示。由于big.Float没有base字段或任何对应的字段,因此它可以&# 39; t实际存储0.10。

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