【问题标题】:Why do floats seem to add incorrectly in Java? [duplicate]为什么浮点数似乎在 Java 中添加不正确? [复制]
【发布时间】:2011-08-01 18:39:19
【问题描述】:

可能的重复:
Is JavaScript's Math broken?
Java floating point arithmetic

我有当前代码

for(double j = .01; j <= .17; j+=.01){
            System.out.println(j);
        }

输出是:

0.01
0.02
0.03
0.04
0.05
0.060000000000000005
0.07
0.08
0.09
0.09999999999999999
0.10999999999999999
0.11999999999999998
0.12999999999999998
0.13999999999999999
0.15
0.16
0.17

有人可以解释为什么会这样吗?你如何解决这个问题?除了写取整函数?

【问题讨论】:

  • @JW:这是一个非常有用的链接,考虑到它回答的(类似)问题的数量以及它完整、正确、简短易读的事实。非常感谢。
  • @matt:我希望人们停止发布该链接。这不是一个很好的参考,除非你想读一本小书只是为了了解浮点数是如何工作的(真的没那么复杂!)
  • @BlueRaja 我不同意,我认为这是一个很好的参考,表明浮点数学是一个非常复杂的野兽,它比将十进制数字相加复杂得多

标签: java math


【解决方案1】:

由于它们的存储方式,浮点数是 Java 中实际数字的近似值。如果您需要精确值,请改用BigDecimal

【讨论】:

    【解决方案2】:

    它们工作正常。一些十进制值不能用二进制浮点数精确表示,而是四舍五入到最接近的值。有关更多详细信息,请参阅我对 this question 的回答。这个问题是关于 Perl 的,但答案同样适用于 Java,因为它是对所有没有无限精度的浮点表示(即所有浮点表示)的限制。

    【讨论】:

      【解决方案3】:

      正如@Kaleb Brasee 所建议的那样,当必须准确时,请使用 BigDecimal。这是一个链接,可以很好地解释与在 Java 中使用浮点运算相关的微小细节http://firstclassthoughts.co.uk/java/traps/java_double_traps.html

      还有一个链接指向使用 BigDecimal 所涉及的问题。强烈建议阅读它们。它真的帮助了我。 享受吧,波罗。

      【讨论】:

        【解决方案4】:

        在电脑上双重表示是正常的。你失去了一些位然后你会得到这样的结果。更好的解决方案是这样做:

        for(int j = 1; j <= 17; j++){
            System.out.println(j/100.0);
        }
        

        【讨论】:

          【解决方案5】:

          这是因为浮点值本质上与数学意义上的实数不同。

          在计算机中,只有固定数量的位可用于表示值。这意味着它可以保存的值是有限的。但是实数的数量是无限的,因此并不是所有的都可以精确地表示。但通常该值是接近的。你可以找到更详细的解释here

          【讨论】:

            【解决方案6】:

            这是因为IEEE754 二进制格式的限制,无法充分利用 32 位。

            【讨论】:

              【解决方案7】:

              当我们“手动”处理浮点数时(即字面上写在纸上或将它们输入计算机时),我们人类习惯于以“以 10 为基数”进行思考。正因为如此,我们有可能写下一个精确的表示,比如 17%。我们只写 0.17(或 1.7E-1 等)。试图将这种微不足道的事情表示为第三个不能完全用那个系统来完成,因为我们必须用无限个 3 来写 0.3333333...,这是不可能的。

              处理浮点数的计算机不仅有有限的位数来表示数字的尾数(或有效位),而且它们也被限制以二为底表示尾数。这意味着大多数百分比(我们人类使用以 10 为底的浮点约定总是可以精确写出,例如“0.17”)不可能让计算机精确存储.像 0%、25%、50%、75% 和 100% 这样的分数可以在计算机中完全表示为浮点数,因为它由一半 (2E-1) 或四分之一 ( 2E-4) 非常适合数字的数字表示。像 17% 甚至微不足道的百分比值(对我们人类来说!!)像 10% 或 1% 这样的百分比值对于计算机来说是不可能完全存储的,因为这些数字对于二进制浮点系统来说是“三分之一”的意思人类(base 10)浮点系统。

              但是如果你仔细选择你的浮点值,所以它们总是由整数 1/2^n 组成,其中 n 可能是 10(意味着 1/1024 的整数),那么它们总是可以存储完全正确作为浮点数没有错误。因此,如果您尝试将 17/1024 存储在计算机中,它会顺利进行。即使使用 'human base 10' 十进制系统,您实际上也可以毫无错误地存储它(但您会因必须处理的实际位数而发疯)。

              这就是为什么我认为某些游戏以一个单位表示角度的原因,其中一个完整的 360 度转弯是 256 个角度单位。可以无损失地表示为 0 到 1 之间的浮点数(其中 1 表示您转了一圈)。

              【讨论】:

              • 一般答案是正确的,但关于角度的注释通常是错误的。在所有三角函数计算中(根据游戏..),您将结束使用双精度和正弦/余弦函数,并且从 ASCII 表示到浮点/双精度的舍入对游戏没有影响:0.0001 辐射的误差对在 2D 中绘制场景没有影响或 3D...
              【解决方案8】:

              正如其他人所指出的,只有作为 2 的幂的组合的数字才能以(二进制)浮点格式精确表示

              如果您需要以任意精度存储任意数字,请使用 BigDecimal。

              如果问题只是显示问题,那么您可以在显示数字的方式上解决这个问题。例如:

              String.format("%.2f", n)

              会将数字格式化为小数点后 2 位。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-09-30
                相关资源
                最近更新 更多