如何用浮点运算解决精度误差
How to resolve the accuracy error with floating point arithmetic
我正在尝试制作一个程序来计算给定金额的等量找零。在我精打细算之前,程序中的所有内容都运行良好。当我精打细算时,我做了太多的浮点运算,以至于数值变得不准确。这是输出:
正如我们所见,不是 0.2(我会除以 0.1 得到 2,正确答案),而是 019999999999959064(除以 0.01 得到便士的数量,我们得到 1 而不是2).我该如何解决这个问题,才能获得正确数量的美分?
你不能。浮点不是建模精确货币值的好选择。
要么 (i) 使用 long
类型并以便士为单位工作,要么 (ii) 使用 class 设计的货币模型。
Math.round 是解决此问题的一种方法,但我不推荐它。
另一种方法是使用 BigDeciaml,它更准确,尤其是在处理货币时
我最近读到的另一种方法是计算整数直到结束,例如以美分而不是美元计算,因此 1 美元将变成 100,然后从那里开始计算。
希望这些想法对您有所帮助
谩骂
停止使用浮点数来表示货币。
BigDecimal 同样糟糕,但精度(可能 none)问题较少。
如果您使用 BigDecimal,
我建议您在代码中包含以下注释:
// Danger, this code written by a goofball (insert your name here).
真正的解决方案
使用多头并表示从有意义的(对您的情况而言)一分钱的一小部分开始的值;也许是一分钱的千分之一。
即使你代表一分钱的百万分之一,
很长的时间仍然提供了足够的空间来显着超过
9,223,372,036.99 美元
这可能比您需要处理的任何交易都大。
您需要使用适当的舍入。即使您使用 long
或 BigDecimal
舍入问题也不会消失,但在这种情况下会简单得多。
一个好的开始是四舍五入到 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 来执行此操作,但是您需要对每个步骤进行舍入,这在本例中更为复杂。
我正在尝试制作一个程序来计算给定金额的等量找零。在我精打细算之前,程序中的所有内容都运行良好。当我精打细算时,我做了太多的浮点运算,以至于数值变得不准确。这是输出:
正如我们所见,不是 0.2(我会除以 0.1 得到 2,正确答案),而是 019999999999959064(除以 0.01 得到便士的数量,我们得到 1 而不是2).我该如何解决这个问题,才能获得正确数量的美分?
你不能。浮点不是建模精确货币值的好选择。
要么 (i) 使用 long
类型并以便士为单位工作,要么 (ii) 使用 class 设计的货币模型。
Math.round 是解决此问题的一种方法,但我不推荐它。
另一种方法是使用 BigDeciaml,它更准确,尤其是在处理货币时
我最近读到的另一种方法是计算整数直到结束,例如以美分而不是美元计算,因此 1 美元将变成 100,然后从那里开始计算。
希望这些想法对您有所帮助
谩骂
停止使用浮点数来表示货币。 BigDecimal 同样糟糕,但精度(可能 none)问题较少。
如果您使用 BigDecimal, 我建议您在代码中包含以下注释:
// Danger, this code written by a goofball (insert your name here).
真正的解决方案
使用多头并表示从有意义的(对您的情况而言)一分钱的一小部分开始的值;也许是一分钱的千分之一。 即使你代表一分钱的百万分之一, 很长的时间仍然提供了足够的空间来显着超过 9,223,372,036.99 美元 这可能比您需要处理的任何交易都大。
您需要使用适当的舍入。即使您使用 long
或 BigDecimal
舍入问题也不会消失,但在这种情况下会简单得多。
一个好的开始是四舍五入到 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 来执行此操作,但是您需要对每个步骤进行舍入,这在本例中更为复杂。