在 Go 中将货币从浮点数转换为整数的最佳方法是什么?
------------- 增加了问题的解释 ----------
为了稍微扩展我的问题,以下是我认为通过添加 0.004 的舍入值(对于 2 位十进制货币)解决的“问题”的示例。
据我所知,外部值存储为例如。RDBMS 中的十进制、双精度、货币需要作为浮点数“导入”到 Go。为了执行计算,然后需要将它们转换为整数,或者至少这是一种方法。
在下面的示例中,fVal1 模拟从数据库导入的金额。要对其执行计算,我想将其转换为整数。在我看来,最简单的方法是添加一个如图所示的舍入数字。
示例代码:
var fVal1 float64 = 19.08
var f100 float64 = 100.0
var fRound float64 = 0.004
var fResult float64 = fVal1 * f100
fmt.Printf("%f * %f as float = %f\n", fVal1, f100, fResult)
var iResult1 int64 = int64(fResult)
fmt.Printf("as Integer unrounded = %d\n", iResult1)
var iResult2 int64 = int64(fResult + fRound)
fmt.Printf("as Integer rounded = %d\n", iResult2)
控制台输出:
19.080000 * 100.000000 as float = 1908.000000
as Integer unrounded = 1907
as Integer rounded = 1908
------------问题补充结束------------
我已经实现了一个小包来处理 Go 中的多种货币,基本上它围绕以下代码(如下)。
当我发现浮点数和整数之间的转换存在舍入错误时,我尝试的第一个舍入因子是 0.004(对于 2 位小数),它似乎工作正常。
基本上,以下用于从 float 到 int 的货币转换的代码围绕这两个替代代码行:
var iCcyAmt1 int64 = int64(fCcyBase * fScale)
var iCcyAmt2 int64 = int64((fCcyBase + fRound) * fScale)
第二种选择中“fRound”中使用的舍入是“0.004”。
运行这个测试程序(1000 万次迭代)会导致一致的舍入误差约为 588,000 美分,其中未添加“0.004”,并且使用舍入数字的差异为零。
这是处理这种情况的安全方法(我不想使用字符串),还是有更好的方法?
测试程序:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
var (
fRound float64 = 0.004
fScale float64 = 100.0
iCcyTotBase int64
iCcyTot1 int64
iCcyTot2 int64
)
const I_ITERS int = 10000000
rand.Seed(time.Now().UTC().UnixNano())
fmt.Printf("\nTesting Float to Integer (%d iterations)"+
" .........", I_ITERS)
for i := 0; i < I_ITERS; i++ {
var iCcyBase int64 = int64(999 + rand.Intn(9999999))
var fCcyBase float64 = float64(iCcyBase) / fScale
var iCcyAmt1 int64 = int64(fCcyBase * fScale)
var iCcyAmt2 int64 = int64((fCcyBase + fRound) * fScale)
iCcyTotBase += iCcyBase
iCcyTot1 += iCcyAmt1
iCcyTot2 += iCcyAmt2
}
var iCcyDiff1 int64 = iCcyTot1 - iCcyTotBase
var iCcyDiff2 int64 = iCcyTot2 - iCcyTotBase
fmt.Printf("\nDiff without rounding = %d\n", iCcyDiff1)
fmt.Printf("Diff with rounding = %d\n", iCcyDiff2)
}