如何避免Java中的浮点数或双精度浮点精度错误?

tun*_*nuz 30 java sum floating-accuracy

我有一个非常恼人的问题,在Java中有很多浮点数或双打数.基本上这个想法是,如果我执行:

for ( float value = 0.0f; value < 1.0f; value += 0.1f )
    System.out.println( value );
Run Code Online (Sandbox Code Playgroud)

我得到的是:

0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.70000005
0.8000001
0.9000001
Run Code Online (Sandbox Code Playgroud)

我明白浮动精度误差的积累,但是,如何摆脱这个?我尝试使用双打错误的一半,但结果仍然相同.

有任何想法吗?

Mar*_*ers 33

没有精确表示0.1作为floatdouble.由于此表示错误,结果与您的预期略有不同.

您可以使用以下几种方法:

  • 使用该double类型时,只显示所需数量的数字.检查相等性时,允许任何一种小容差.
  • 或者使用一种类型,允许您存储您想要准确表示的数字,例如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);
}
Run Code Online (Sandbox Code Playgroud)

在线查看:ideone


T.J*_*der 9

你可以使用像这样的类来避免这个特定问题BigDecimal.float并且double,作为IEEE 754浮点,它们的设计并不完全准确,它们的设计速度很快.但请注意Jon的观点如下:BigDecimal不能准确地代表"三分之一",double不能准确地代表"十分之一".但是对于(比如说)财务计算,BigDecimal类似的课程往往是要走的路,因为它们可以用我们人类倾向于思考它们的方式来表示数字.

  • 这不是"精确"和"不精确"的问题 - 这是每种类型可以表示的问题.BigDecimal不再能够完全代表"三分之一"而不能完全代表"十分之一". (12认同)

Pet*_*rey 7

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

for (int i = 0; i < 10; i++)
    System.out.println(i / 10.0);
Run Code Online (Sandbox Code Playgroud)

它打印

0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
Run Code Online (Sandbox Code Playgroud)

我知道BigDecimal是一个受欢迎的选择,但我更喜欢双倍,因为它更快但通常更短/更清晰.

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

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

BTW:除非有不使用浮动真的很好的理由不使用双.