如何在Java中使用浮点数或浮点数来避免浮点精度错误?

我有一个非常烦人的问题,在Java中花了很长时间的花车或双打。 基本上这个想法是,如果我执行:

for ( float value = 0.0f; value < 1.0f; value += 0.1f ) System.out.println( value ); 

我得到的是:

 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.70000005 0.8000001 0.9000001 

我明白,浮动精度错误有一个积累,但是,如何摆脱这个? 我试图使用双打一半的错误,但结果仍然是一样的。

有任何想法吗?

0.1没有一个floatdouble floatexpression式。 由于这种表示错误,结果与您的预期略有不同。

你可以使用几种方法:

  • 使用double型时,只显示所需数量的数字。 当检查平等允许任何方式的小容忍。
  • 或者,使用允许您存储准确表示的数字的types,例如BigDecimal可以精确地表示0.1。

BigDecimal示例代码:

 BigDecimal step = new BigDecimal("0.1"); for (BigDecimal value = BigDecimal.ZERO; value.compareTo(BigDecimal.ONE) < 0; value = value.add(step)) { System.out.println(value); } 

在线查看: ideone

你可以使用像BigDecimal这样的类来避免这个特定的问题。 floatdouble float ,IEEE 754浮点,不是精确的devise,它们devise得很快。 但请注意Jon的要点: BigDecimal不能准确地表示“三分之一”,任何超过二分之一的准确表示“十分之一”。 但是对于(比方说)财务计算, BigDecimal和类似的类往往是要走的路,因为它们可以用我们人类倾向于考虑的方式来表示数字。

不要在迭代器中使用float / double,因为这会最大化舍入误差。 如果你只是使用以下

 for (int i = 0; i < 10; i++) System.out.println(i / 10.0); 

它打印

 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 

我知道BigDecimal是一个stream行的select,但我更喜欢双倍,不是因为它更快,但它通常要更短或更清晰的理解。

如果您计算符号的数量作为代码复杂性的度量

  • 使用double => 11个符号
  • 使用BigDecimal(来自@Mark Byers示例)=> 21个符号

顺便说一句:不要使用浮动,除非有一个很好的理由不使用双。

这不仅仅是一个累积的错误(与Java完全没有关系)。 1.0f ,一旦翻译成实际的代码,不具有0.1的值 – 你已经得到一个四舍五入的错误。

从浮点指南:

我能做些什么来避免这个问题?

这取决于你在做什么样的计算。

  • 如果你真的需要你的结果加起来,特别是当你使用金钱:使用一个特殊的十进制数据types。
  • 如果您不想看到所有这些额外的小数位:只需在显示时将结果格式化为固定的小数位数。
  • 如果你没有可用的小数数据types,另一种方法是使用整数,例如完全以美分计算。 但这是更多的工作,并有一些缺点。

阅读链接到的网站获取详细信息。

为了完整起见,我推荐这个:

Shewchuck,“稳健的自适应浮点几何谓词”,如果你想要更多的例子来说明如何进行精确的浮点计算 – 或者至less是作者的初衷是控制精度。埃杜/〜JRS /纸/ robustr.pdf

另一个解决scheme是放弃==并检查两个值是否足够接近 。 (我知道这不是你所要求的,但是我正在回答问题的标题。)

我遇到了同样的问题,使用BigDecimal解决了同样的问题。 以下是帮助我的片段。

 double[] array = {45.34d, 45000.24d, 15000.12d, 4534.89d, 3444.12d, 12000.00d, 4900.00d, 1800.01d}; double total = 0.00d; BigDecimal bTotal = new BigDecimal(0.0+""); for(int i = 0;i < array.length; i++) { total += (double)array[i]; bTotal = bTotal.add(new BigDecimal(array[i] +"")); } System.out.println(total); System.out.println(bTotal); 

希望它会帮助你。

你应该使用十进制数据types,而不是浮动:

https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

 package loopinamdar; import java.text.DecimalFormat; public class loopinam { static DecimalFormat valueFormat = new DecimalFormat("0.0"); public static void main(String[] args) { for (float value = 0.0f; value < 1.0f; value += 0.1f) System.out.println("" + valueFormat.format(value)); } } 

如果你想继续使用float并避免通过反复添加0.1f累积错误,请尝试如下所示:

 for (int count = 0; count < 10; count++) { float value = 0.1f * count; System.out.println(value); } 

但是请注意,正如其他人已经解释的那样, float不是一个无限精确的数据types。

您只需要知道您的计算所需的精度以及所选数据types的精度,并相应地显示您的答案。

例如,如果您处理的是具有3位有效数字的数字,则使用float (提供7位有效数字的精度)是适当的。 但是,如果您的起始值只有2位有效数字的精度,则无法引用您的最终答案,即7位有效数字的精度。

 5.01 + 4.02 = 9.03 (to 3 significant figures) 

在你的例子中,你正在执行多个添加,每增加一个结果就会对最终的精度产生影响。