如果您使用 double 将货币值转换为另一种货币并返回,您可能会损失的最精确度是多少?

What's the most precision you might lose if you use double to convert a currency value to another currency and back?

我知道由于基数 2 计算导致的双打问题:

var total: Double = 0.1
total *= 0.1
total /= 0.1
println(total) // 0.10000000000000002

我知道 BigDecimal 应该用于与货币相关的计算,但在我的情况下,小的精度损失是可以接受的,因为我需要做的所有货币计算都是将货币 C1 转换为货币 C2,然后再转换回货币 C1。唯一的问题是,当我以 5 位小数精度向客户显示结果时,此转换后的 C1 的两个值应该匹配。

现在我想弄清楚,在最坏的情况下,此转换的价值可能会漂移多少?可能导致最坏情况的数字是多少?

我建议永远不要在任何地方存储或转移 C2 金额。相反,存储或传输 C1 金额和汇率。这样,您可以在需要时计算和显示 C2 数量,并且始终可以获得准确的原始 C1 值。

如果您绝对必须存储 C2 并稍后从中重新计算 C1,只要您使用舍入而不是截断就没问题,因为您冒着重新计算结果的风险,例如0.0199999999999。 (正如@Andreas 在他的回答中指出的那样,您可以通过这种方式支持多少位数。)

您可以阅读 double-precision floating-point 的描述:

The 11 bit width of the exponent allows the representation of numbers with a decimal exponent between 10^−308 and 10^308, with full 15–17 decimal digits precision.

因为你想要 5 个小数位数,这意味着你可以达到最大值。 10位整数。

或者你可以测试一下。有时经验证据更有说服力:

double value = 0.00009;
while (true) {
    String nextDown = String.format("%.5f", Math.nextDown(value));
    String nextUp   = String.format("%.5f", Math.nextUp(value));
    if (! nextDown.equals(nextUp))
        break; // loss of precision to 5 decimals
    System.out.printf("Good: %.5f%n", value);
    value = value * 10 + 0.00009;
}
System.out.printf("Bad: %.5f%n", value);

输出

Good: 0.00009
Good: 0.00099
Good: 0.00999
Good: 0.09999
Good: 0.99999
Good: 9.99999
Good: 99.99999
Good: 999.99999
Good: 9999.99999
Good: 99999.99999
Good: 999999.99999
Good: 9999999.99999
Good: 99999999.99999
Good: 999999999.99999
Good: 9999999999.99999
Bad: 99999999999.99997

是的,10 分好,11 分差。

A doublebinary64 将保持 15+ 显着 小数位如果适当四舍五入 to/from 小数。

使用固定位数学:15 有效 小数位和 OP 需要在小数点后 5 位,即小数点左边有 10 位数字。

x,xxx,xxx,xxx.xxxxx