Go-货币计算

  • 本文关键字:计算 货币 Go- 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
看来我可以把它用于我的目的(但我不确定…)

我的问题是

  1. 为什么使用Float.SetFloat64()Float.SetString()有区别?

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

提前谢谢,原谅我的英语。

[编辑]

我知道应该避免使用浮动类型来表示货币价值
但是这种类型的选择并不是我能控制的。。

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

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

永远不要使用浮动汇率。这是一种不精确的类型,所以你最终不得不四舍五入计算,你最终会在这里或那里损失(或获得)一分钱。你可能认为这没关系,但你的会计师会告诉你不是。您必须完全准确。

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

PS。永远不要使用浮动汇率。真正地

PPS。不要使用浮动汇率,永远不要。

使用代表千分之一或一万分之一美分的big.Int值。浮点值不适合货币,尤其是在交易时。如果有人要求你使用浮点值,试着说服他们这是个坏主意。如果这不起作用,请重新考虑与他们合作的决定。考虑一下你可能无意中卷入了一些非法的事情:https://en.wikipedia.org/wiki/Salami_slicing

回答您的技术问题:

CCD_ 13值不像CCD_ 14值那样是任意精度。

SetFloat64将浮点的精度设置为float64的精度,而SetString则根据字符串的内容进行设置。

无论哪种方式,你都要非常慎重地考虑你在大屏幕上设置的精度。浮点值。您可以使用SetPrec进行控制https://golang.org/pkg/math/big/#Float.SetPrec

编辑:

至于陷阱,考虑基数10中的0.10在基数2中没有有限表示。由于CCD_ 19没有CCD_。

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

您可以使用实现"无限精度"十进制算术的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。

最新更新