【发布时间】:2013-10-08 02:37:44
【问题描述】:
在 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)
}
【问题讨论】:
-
看看“数学/大”?这可能就是你想要的。 (即使我仍然没有完全理解你的问题)
-
我也不明白你的问题。浮点操作中存在 no 舍入错误,因为出现不可预知的错误。写下您期望从“float to int”转换中获得的数学属性。根据您的要求,您将不得不使用 big.Rat 或可能坚持使用浮动处理。
-
看看blog.stata.com/tag/precision/#section7 。它提到了几件事: 1. “2011 年美国的赤字为 1.5 万亿美元。以浮动形式存储,这个数额的(最大)误差为 ±2-24*1.5e+12 = ±89,406.97 美元。” 2、当需要精度时,“货币数据应转换为整数(便士)并存储为整数”。显然这是美国特有的,但应该适用于大多数货币。
-
我用另一个例子扩展了我的问题,以说明我想要实现的目标。
-
实际上,我永远不会将货币数据存储在浮点数中。我总是为此使用定点算术。例如,如果 1 美分的精度就足够了,我会将 123 美元存储为 12300(美分)。使用浮点运算会给你带来麻烦。
标签: go