Closed. This question is opinion-based。它当前不接受答案。
想改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。
在11个月前关闭。
Improve this question
我知道这个问题已经讨论过几次了,但是我对答案并不完全满意。请不要回答“双精度数不正确,您不能代表0.1!您必须使用BigDecimal” ...
基本上,我在做财务软件,我们需要在内存中存储很多价格。 BigDecimal太大,无法容纳在缓存中,因此我们决定切换为double。
到目前为止,由于充分的原因,我们还没有遇到任何错误,我们需要12位数字的准确性。 12位数字的估算是基于这样的事实,即使我们以百万为单位讲话,我们仍然能够处理美分。
双精度数提供15位有效的十进制数字精度。如果您在必须显示/比较双打时对其进行四舍五入,那会出什么问题?
我猜问题在于积累的不准确性,但是有多糟糕呢?在影响第12位数字之前需要进行多少次操作?
您是否发现双打还有其他问题?
编辑:大约很长一段时间,这绝对是我们考虑过的事情。我们正在做很多除法运算,但长期以来并不能很好地处理(丢失小数和溢出),或者至少您必须非常小心自己的操作。我的问题更多地是关于双打理论,基本上它有多糟糕,并且这种误差是否可以接受?
EDIT2:不要尝试解决我的软件,我的准确性不高:)。我重新措辞一个问题:如果只需要12位数字,并且在显示/比较时四舍五入为双精度数字,发生不准确的可能性有多大?
结果如下:
请注意,累积误差的大小并没有与中间步骤的数量成正比地增加(实际上,并不是单调地增加)。给定一系列已知的中间操作,我们可以确定不准确性的概率分布;尽管操作范围更广,但操作更多,确切的数量将取决于计算中输入的数字。不确定性本身就是不确定性!
根据您执行的计算类型,您可以通过在中间步骤后四舍五入到整数/整分来控制此错误。 (考虑到一个银行帐户持有100美元,年利率为6%的复合利率,因此每月为0.5%的利息。贷记第三个月的利息后,您是否希望余额为101.50美元或101.51美元?)因为小数单位(即美分)的数量而不是整数单位的数量将使此操作变得更容易-但是,如果要这样做,您也可以按照我上面的建议使用
同样,免责声明:浮点错误的累积使
想改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。
在11个月前关闭。
Improve this question
我知道这个问题已经讨论过几次了,但是我对答案并不完全满意。请不要回答“双精度数不正确,您不能代表0.1!您必须使用BigDecimal” ...
基本上,我在做财务软件,我们需要在内存中存储很多价格。 BigDecimal太大,无法容纳在缓存中,因此我们决定切换为double。
到目前为止,由于充分的原因,我们还没有遇到任何错误,我们需要12位数字的准确性。 12位数字的估算是基于这样的事实,即使我们以百万为单位讲话,我们仍然能够处理美分。
双精度数提供15位有效的十进制数字精度。如果您在必须显示/比较双打时对其进行四舍五入,那会出什么问题?
我猜问题在于积累的不准确性,但是有多糟糕呢?在影响第12位数字之前需要进行多少次操作?
您是否发现双打还有其他问题?
编辑:大约很长一段时间,这绝对是我们考虑过的事情。我们正在做很多除法运算,但长期以来并不能很好地处理(丢失小数和溢出),或者至少您必须非常小心自己的操作。我的问题更多地是关于双打理论,基本上它有多糟糕,并且这种误差是否可以接受?
EDIT2:不要尝试解决我的软件,我的准确性不高:)。我重新措辞一个问题:如果只需要12位数字,并且在显示/比较时四舍五入为双精度数字,发生不准确的可能性有多大?
最佳答案
如果您绝对不能使用BigDecimal
并且不想使用double
,请使用long
来执行fixed-point arithmetic(例如,每个long
值将代表美分)。这将使您代表18个有效数字。
我会说使用joda-money,但这在幕后使用了BigDecimal
。
编辑(因为以上内容并未真正回答问题):
免责声明:如果准确性对您很重要,请don't use double
to represent money。但是似乎发布者并不需要确切的准确性(这似乎是一种金融定价模型,该模型可能具有10 **-12以上的内置不确定性),并且更在意性能。假设是这种情况,可以使用double
。
通常,double
不能精确表示十进制分数。那么,double
是多么不精确?没有简短的答案。double
可能足以表示一个数字,您可以将其读入double
中,然后再次写回,保留15位精度的十进制数字。但是因为它是二进制而不是小数,所以它不是精确的-它是我们希望表示的值,加上或减去一些错误。当执行许多涉及不精确double
的算术运算时,随着时间的流逝,此错误的数量会逐渐增加,从而最终产品的准确度少于15个十进制数字。少几个?那要看。
考虑以下函数,该函数将n
的根数取为1000,然后将其自身乘以n
的次数:
private static double errorDemo(int n) {
double r = Math.pow(1000.0, 1.0/n);
double result = 1.0;
for (int i = 0; i < n; i++) {
result *= r;
}
return 1000.0 - result;
}
结果如下:
errorDemo( 10) = -7.958078640513122E-13
errorDemo( 31) = 9.094947017729282E-13
errorDemo( 100) = 3.410605131648481E-13
errorDemo( 310) = -1.4210854715202004E-11
errorDemo( 1000) = -1.6370904631912708E-11
errorDemo( 3100) = 1.1107204045401886E-10
errorDemo( 10000) = -1.2255441106390208E-10
errorDemo( 31000) = 1.3799308362649754E-9
errorDemo( 100000) = 4.00075350626139E-9
errorDemo( 310000) = -3.100740286754444E-8
errorDemo(1000000) = -9.706695891509298E-9
请注意,累积误差的大小并没有与中间步骤的数量成正比地增加(实际上,并不是单调地增加)。给定一系列已知的中间操作,我们可以确定不准确性的概率分布;尽管操作范围更广,但操作更多,确切的数量将取决于计算中输入的数字。不确定性本身就是不确定性!
根据您执行的计算类型,您可以通过在中间步骤后四舍五入到整数/整分来控制此错误。 (考虑到一个银行帐户持有100美元,年利率为6%的复合利率,因此每月为0.5%的利息。贷记第三个月的利息后,您是否希望余额为101.50美元或101.51美元?)因为小数单位(即美分)的数量而不是整数单位的数量将使此操作变得更容易-但是,如果要这样做,您也可以按照我上面的建议使用
double
。同样,免责声明:浮点错误的累积使
long
的使用可能会带来很多麻烦。作为一名Java开发人员,他使用double
来表示多年来输入到他的任何东西的十进制表示法是邪恶的,对于涉及金钱的任何重要计算,我都会使用十进制而不是浮点运算。