如何用Go代表货币?

Dan*_*nte 7 currency go

在Go中存储和对货币进行算术运算的正确方法是什么?似乎没有相应的十进制类型,使用浮点数是一个很大的问题.

小智 9

这似乎是创建类型的绝佳机会,它以安全且精确的基于整数的方式存储值,但为您提供了您想要的十进制类型的额外行为。例如,快速实现可能如下所示(https://play.golang.org/p/nYbLiadQO​​c):

// USD represents US dollar amount in terms of cents
type USD int64

// ToUSD converts a float64 to USD
// e.g. 1.23 to $1.23, 1.345 to $1.35
func ToUSD(f float64) USD {
    return USD((f * 100) + 0.5)
}

// Float64 converts a USD to float64
func (m USD) Float64() float64 {
    x := float64(m)
    x = x / 100
    return x
}

// Multiply safely multiplies a USD value by a float64, rounding
// to the nearest cent.
func (m USD) Multiply(f float64) USD {
    x := (float64(m) * f) + 0.5
    return USD(x)
}

// String returns a formatted USD value
func (m USD) String() string {
    x := float64(m)
    x = x / 100
    return fmt.Sprintf("$%.2f", x)
}
Run Code Online (Sandbox Code Playgroud)

给定类型的行为与人们预期的一样,特别是考虑到棘手的用例。

fmt.Println("Product costs $9.09. Tax is 9.75%.")

f := 9.09
t := 0.0975
ft := f * t
fmt.Printf("Floats: %.18f * %.18f = %.18f\n", f, t, ft)

u := ToUSD(9.09)
ut := u.Multiply(t)
fmt.Printf("USD:    %v * %v = %v\n", u, t, ut)
Run Code Online (Sandbox Code Playgroud)

产品售价 9.09 美元。税率为 9.75%。

浮点数:9.089999999999999858 * 0.097500000000000003 = 0.886275000000000035

美元:9.09 美元 * 0.0975 = 0.89 美元


kos*_*tix 8

我想说一种方法是使用适当大小的整数类型来存储金额,并将其标准化为可能的最低金额.比如说,如果您需要以美元存储金额低至1美分,请将您的价值乘以100,然后将它们存储在全部美分中.

另一种方法是实现一个自定义类型,它可以模拟某些其他语言中的"十进制",也就是说,它会使用两个整数来表示金额.

  • JFTR,为 Go 实现定点十进制数(适用于货币计算)的软件包确实存在;一个例子是 [`github.com/shopspring/decimal`](https://github.com/shopspring/decimal)。 (5认同)
  • 我喜欢这个主意。定义一个包含两个整数(整数和小数)的结构体,然后您可以为您的货币类型声明自定义方法,包括转换等。 (2认同)

Ric*_*777 6

有理数是表示货币价值的一个很好的解决方案。即,具有分子和分母的类型。

通常货币数据结构过于复杂——Java 的 BigDecimal 就是一个例子。一种在数学上更一致的方法是定义一种处理有理数的类型。当使用 64 位整数时,可以准确有效地表示大量数字。与需要将二进制分数转换为/从十进制分数转换的任何解决方案相比,错误和舍入问题都不是问题。

编辑:Go 标准库包括任意精度整数和有理数。Rat 类型适用于货币,特别是对于那些需要任意精度的情况,例如外汇。这是一个例子

编辑 2:我广泛使用了decimal.Decimal Shopspring 软件包。在幕后,这big.Int与指数相结合以提供具有几乎无限范围值的定点小数。该Decimal类型是有理数分母始终是10的幂,这在实践中工作得非常好。


jus*_*nas 5

实际上有一些包实现了十进制类型,尽管其中没有明确的领导者。

  • 看起来现在有一个明显的领导者:https://github.com/shopspring/decimal (2认同)