浮点运算不产生精确结果

新手上路,请多包涵

我需要在 Java 中做一些浮点运算,如下面的代码所示:

 public class TestMain {
    private static Map<Integer, Double> ccc = new HashMap<Integer, Double>() {
      { put(1, 0.01); put(2, 0.02); put(3, 0.05); put(4, 0.1); put(6, 0.2);
        put(10, 0.5); put(20, 1.0); put(30, 2.0); put(50, 5.0); put(100, 10.0);
      }
    };

    Double increment(Double i, boolean up) {
        Double inc = null;

        while (inc == null) {
            inc = ccc.get(i.intValue());

            if (up)
                --i;
            else
                ++i;
        }
        return inc;
    }

    public static void main(String[] args) {
        TestMain tt = new TestMain();

        for (double i = 1; i < 1000; i += tt.increment(i, true)) {
            System.out.print(i + ",");
        }
    }
}

这是为了模拟由 Betfair 微调器小部件 输出的值的范围。

Java 中的浮点运算似乎引入了一些意想不到的错误。例如,我得到 2.180000000000001 而不是 2.18。浮点数有什么用你不能相信对它们执行的算术结果?我怎样才能解决这个问题?

原文由 user63904 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 262
2 个回答

浮点数使用二进制小数而不是小数。也就是说,你已经习惯了由十分位、百位、千位等组成的小数。 d1/10 + d2/100 + d3/1000 …但是浮点数是二进制的,所以他们有半数,四分之一,八分之一等。 d1/2 + d2/4 + d3/8 …

许多小数不能用任何有限数量的二进制数字精确表示。例如,1/2 没有问题:十进制为 .5,二进制为 .1。 34 是十进制的 .75,二进制的 .11。但是 110 在十进制中是一个干净的 .1,但在二进制中它是 .0001100110011…“0011”永远重复。由于计算机只能存储有限数量的数字,因此在某些时候必须将其截断,因此答案并不准确。当我们在输出中转换回十进制时,我们得到一个看起来很奇怪的数字。

正如 Jon Skeet 所说,如果您需要精确的小数,请使用 BigDecimal。如果性能有问题,您可以滚动自己的小数部分。比如,如果你知道你总是想要精确的 3 位小数并且数字不会超过一百万左右,你可以简单地使用 int 和假设的 3 位小数,在你做算术和写输出时根据需要进行调整format 函数在正确的位置插入小数点。但在 99% 的时间里,性能并不是一个大到值得为此烦恼的问题。

原文由 Jay 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题