繁体   English   中英

如何用浮点运算解决精度误差

[英]How to resolve the accuracy error with floating point arithmetic

我正在尝试制定一个计算给定金额的等价变化量的程序。 程序中的所有内容都运行良好,直到我得到便士。 当我得到便士时,我已经做了很多浮点算术,这个值变得不准确。 这是输出:

在此输入图像描述

我们可以看到,而不是0.2(我将除以0.1得到2,正确答案),我们有019999999999959064(当除以0.01得到便士的数量时,我们得到1而不是2)。 如何解决这个问题,以便获得正确数量的便士?

你不能。 浮点不是建模精确货币值的好选择。

(i),使用long型并使用便士,或(ii)使用旨​​在模拟金钱的类。

诽谤

停止使用浮点表示货币。 BigDecimal同样糟糕,但精度较低(可能没有)。

如果您使用BigDecimal,我建议您在代码中包含以下注释:

// Danger, this code written by a goofball (insert your name here).

真正的解决方案

使用long并表示从一个有意义的(对你的情况)一小部分开始的值; 也许是一分钱的1000分。 即使您代表1,000,000美元的一分钱,长期仍然提供足够的空间,远远超过$ 9,223,372,036.99,这可能比您需要处理的任何交易都要大。

您需要使用适当的舍入。 即使你使用longBigDecimal舍入问题也不会消失,尽管在这种情况下它会更简单。

一个良好的开始是四舍五入到long数美分。

double value = 586.67;
long v = Math.round(value * 100.0); // the fact you used a double is fine.
long hundreds = v / 100;
v -= hundreds * 100;
long fifties = v / 50;
v -= fifties * 50;
long twenties = v / 20;
v -= twenties * 20;
long tens = v / 10;
v -= tens * 10;

你可以用double做到这一点,但是你需要绕过每一步,这在这个例子中更复杂。

Math.round是解决这个问题的一种方法,但我不推荐它。

另一种方法是使用BigDeciaml,这在处理货币时特别准确

我最近阅读的另一种方式是直到最后工作,例如以美分而不是美元工作,因此$ 1将是100而不是从那里工作。

我希望这些想法有所帮助

一般来说,关于浮点的非常有用的视频

数学api

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM