【问题标题】:Java's '==' operator on doublesJava的'=='双打运算符
【发布时间】:2013-01-21 23:26:01
【问题描述】:

此方法返回“真”。为什么?

public static boolean f() {
   double val = Double.MAX_VALUE/10;
   double save = val;
   for (int i = 1; i < 1000; i++) {
       val -= i;
   }
   return (val == save);
}

【问题讨论】:

  • 因为val 包含的值与save 相同?
  • 这只是“浮点运算是如何工作的?”再次改写。
  • 你错了。 val 不会改变。阅读任何有关浮点运算的书籍或在线文章。
  • 因为从 val 中减去的数字比 val 小几个数量级,并且不会影响其值。 @us2012 当然是正确的。

标签: java floating-point equals-operator


【解决方案1】:

浮点计算的结果是最接近准确答案的可表示值。这个程序:

public class Test {
  public static void main(String[] args) throws Exception {
    double val = Double.MAX_VALUE/10;
    System.out.println(val);
    System.out.println(Math.nextAfter(val, 0));
  }
}

打印:

1.7976931348623158E307
1.7976931348623155E307

这些数字中的第一个是您的原始 val。第二个是小于它的最大双精度数。

当您从 1.7976931348623158E307 中减去 1000 时,确切的答案在这两个数字之间,但非常非常接近 1.7976931348623158E307 而不是 1.7976931348623155E307,因此结果将四舍五入为 1.79769313486231 p>

【讨论】:

    【解决方案2】:

    因为doublefloating point 数值类型,这是一种近似数值的方法。浮点表示对数字进行编码,以便我们可以存储比通常更大或更小的数字。但是,并非所有数字都可以在给定空间中表示,因此多个数字会四舍五入为相同的浮点值。

    作为一个简化的例子,我们可能希望能够在一些通常只能存储 -10 到 10 的小空间中存储范围从 -1000 到 1000 的值。所以我们可以将所有值四舍五入为最接近的千并将它们存储在小空间中:-1000 编码为-10,-900 编码为-9,1000 编码为10。但是如果我们想存储 -999 怎么办?我们可以编码的最接近的值是 -1000,因此我们必须将 -999 编码为与 -1000 相同的值:-10

    实际上,浮点方案比上面的例子复杂得多,但概念是相似的。数字的浮点表示只能表示所有可能数字中的一些,所以当我们有一个不能作为方案的一部分表示的数字时,我们必须将它四舍五入到最接近的可表示值.

    在您的代码中,Double.MAX_VALUE / 10 1000 以内的所有值都会自动四舍五入为Double.MAX_VALUE / 10,这就是计算机认为(Double.MAX_VALUE / 10) - 1000 == Double.MAX_VALUE / 10 的原因。

    【讨论】:

      【解决方案3】:

      Double.MAX_VALUE 太大了,JVM 分不清它和Double.MAX_VALUE-1000 的区别

      如果你从Double.MAV_VALUE 中减去一个小于“1.9958403095347198E292”的数字,结果仍然是Double.MAX_VALUE

      System.out.println(  
                  new BigDecimal(Double.MAX_VALUE).equals( new BigDecimal(  
                              Double.MAX_VALUE - 2.E291) )  
                      ); 
      
      System.out.println(  
                 new BigDecimal(Double.MAX_VALUE).equals( new BigDecimal(  
                              Double.MAX_VALUE - 2.E292) )  
                             ); 
      

      输出:

      是的

      【讨论】:

        【解决方案4】:

        Double.MAX_VALUE 与 1 或 1000 相比是一个巨大的数字。Double.MAX_VALUE-1 通常等于 Double.MAX_VALUE。因此,当将 1 或 1000 减去 Double.MAX_VALUE/10 时,您的代码大致什么都不做。 永远记住:

        1. doubles 或 floats 只是实数的近似值,它们只是有理数,在实数中分布不均
        2. 您应该非常小心地在 doubles 或 floats 之间使用不相近的算术运算符(还有许多其他类似的规则...)
        3. 一般来说,如果您需要任意精度,请不要使用 doubles 或 float

        【讨论】:

          【解决方案5】:

          val 是一个很大的数字,当从中减去1(甚至是1000)时,结果不能正确地表示为double 值。这个数字xx-1的表示是一样的,因为double只有有限的位数来表示无限的数字。

          【讨论】:

            【解决方案6】:

            当您将 val 设置为 Double.MAX_VALUE/10 时,它被设置为大约等于 1.7976931348623158 * 10^307 的值。从中减去 1000 之类的值需要双精度表示,这是不可能的,因此它基本上保持 val 不变。

            根据您的需要,您可以使用BigDecimal 代替double

            【讨论】:

              【解决方案7】:

              double 没有足够的精度来执行您正在尝试的计算。所以结果和初始值一样。

              == 运算符无关。

              【讨论】:

                【解决方案8】:

                您正在从一个 巨大 值中减去一个很小的值(小于 1000)。小值比大值小很多,最接近理论结果的可表示值仍然是原始值。

                基本上这是浮点数工作方式的结果。

                假设我们有一些十进制浮点类型(只是为了简单起见),它只在尾数中存储 5 个有效数字,以及 0 到 1000 范围内的指数。

                您的示例就像写 10999 - 1000... 考虑一下当四舍五入到 5 个有效数字时会产生什么结果。是的,exact 结果是 99999.....9000(999 位),但如果您只能用 5 个有效数字表示值,则最接近的结果是 10999再次。

                【讨论】:

                  猜你喜欢
                  • 2013-11-28
                  • 1970-01-01
                  • 2016-08-18
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多