有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如何在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

我知道浮动精度误差是有积累的,但如何消除呢?我试着用双倍法将误差减半,但结果还是一样

有什么想法吗


共 (6) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

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

    Shewchuck,“鲁棒自适应浮点几何谓词”,如果您想了解更多关于如何使用浮点执行精确算法的示例,或者至少是作者的初衷——http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf

  3. # 3 楼答案

    可以使用^{}之类的类来避免这个特定问题floatdouble是IEEE 754浮点型,它们的设计目的并不是为了达到完美的精度,而是为了快速。但请注意乔恩下面的观点:BigDecimal不能准确地表示“三分之一”,正如double不能准确地表示“十分之一”。但是对于(比如)金融计算,BigDecimal和类似的类往往是一种方式,因为它们可以用我们人类对数字的思考方式来表示数字

  4. # 4 楼答案

    这不是一个累积的错误(与Java完全无关)1.0f一旦转换为实际代码,就没有0.1的值-您已经得到一个舍入错误

    The Floating-Point Guide:

    What can I do to avoid this problem?

    That depends on what kind of calculations you’re doing.

    • If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype.
    • If you just don’t want to see all those extra decimal places: simply format your result rounded to a fixed number of decimal places when displaying it.
    • If you have no decimal datatype available, an alternative is to work with integers, e.g. do money calculations entirely in cents. But this is more work and has some drawbacks.

    有关详细信息,请阅读链接到网站的链接

  5. # 5 楼答案

    不要在迭代器中使用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是一个流行的选择,但我更喜欢double,不是因为它速度快得多,而是它通常要短得多/更容易理解

    如果将符号的数量作为代码复杂性的衡量标准

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

    顺便说一句:除非有很好的理由不使用double,否则不要使用float

  6. # 6 楼答案

    没有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);
    }
    

    在线查看:ideone