这两种方法在Java中是等效的吗?

这两种方法在Java中是等效的吗?,java,floating-point,Java,Floating Point,备选措辞:在Java中,将Double.MIN_值添加到Double会导致不同的Double值吗?(见下面Jon Skeet的评论) 关于Java中最小双精度值的问题有一些答案,在我看来是等价的毫无疑问,这是可行的,但他的解释并没有让我相信这和他的解释有什么不同 Jon的回答使用了以下内容: double d = // your existing value; long bits = Double.doubleToLongBits(d); bits++; d = Double.longBitsT

备选措辞:在Java中,将Double.MIN_值添加到Double会导致不同的Double值吗?(见下面Jon Skeet的评论)

关于Java中最小双精度值的问题有一些答案,在我看来是等价的毫无疑问,这是可行的,但他的解释并没有让我相信这和他的解释有什么不同

Jon的回答使用了以下内容:

double d = // your existing value;
long bits = Double.doubleToLongBits(d);
bits++;
d = Double.longBitsToDouble();
Richards的回答提到了JavaDoc的
Double.MIN\u值

保持最小值的常数 double类型的正非零值, 2-1074. 它等于十六进制 浮点文字 0x0.0000000000001P-1022,也等于 到
Double.longBitsToDouble(0x1L)

我的问题是,
Double.logBitsToDouble(0x1L)
与Jon的
bits++有何不同

Jon的评论集中在基本浮点问题上

这两者之间是有区别的 将Double.MIN_值转换为Double值, 以及增加位模式 代表双重身份。他们是 完全不同的操作,由于 浮点数的计算方法 这些都是存储的。如果你试图添加一个非常 从一个小数字到一个很大的数字, 差别可能很小 最接近的结果与 原著。将1添加到当前 然而,位模式将始终保持不变 更改相应的浮动 点值,尽可能小 在该比例下可见的值

我看不出Jon用Double.MIN_值增加一个长“bits++”的方法有什么不同。什么时候会产生不同的结果

我编写了以下代码来测试这些差异。也许有人可以提供更多/更好的样本双倍数字,或者使用循环查找存在差异的数字

    double d = 3.14159269123456789; // sample double
    long bits = Double.doubleToLongBits(d);
    long bitsBefore = bits;
    bits++;
    long bitsAfter = bits;
    long bitsDiff = bitsAfter - bitsBefore;
    long bitsMinValue = Double.doubleToLongBits(Double.MIN_VALUE);
    long bitsSmallValue = Double.doubleToLongBits(Double.longBitsToDouble(0x1L));

    if (bitsMinValue == bitsSmallValue)
    {
        System.out.println("Double.doubleToLongBits(0x1L) is same as Double.doubleToLongBits(Double.MIN_VALUE)");           
    }        

    if (bitsDiff == bitsMinValue)
    {
        System.out.println("bits++ increments the same amount as Double.MIN_VALUE");
    }

    if (bitsDiff == bitsMinValue)
    {
        d = d + Double.MIN_VALUE;
        System.out.println("Using Double.MIN_VALUE");
    }
    else
    {
        d = Double.longBitsToDouble(bits);
        System.out.println("Using doubleToLongBits/bits++");
    }

    System.out.println("bits before: " + bitsBefore);   
    System.out.println("bits after: " + bitsAfter);
    System.out.println("bits diff: " + bitsDiff);   
    System.out.println("bits Min value: " + bitsMinValue);
    System.out.println("bits Small value: " + bitsSmallValue);  
输出:

Double.doubleToLongBits(Double.longBitsToDouble(0x1L)) is same as Double.doubleToLongBits(Double.MIN_VALUE)
bits++ increments the same amount as Double.MIN_VALUE
Using doubleToLongBits/bits++
bits before: 4614256656636814345
bits after: 4614256656636814346
bits diff: 1
bits Min value: 1
bits Small value: 1

正如乔恩所说:

“如果你尝试添加一点 数字变为一个很大的数字 差别可能很小,以至于 最接近的结果与 原创。”

例如:

// True:
(Double.MAX_VALUE + Double.MIN_VALUE) == Double.MAX_VALUE
// False:
Double.longBitsToDouble(Double.doubleToLongBits(Double.MAX_VALUE) + 1) == Double.MAX_VALUE)
MIN_VALUE
是可表示的最小正双精度,但这并不意味着将其添加到任意双精度中会导致不相等的双精度


相反,将1添加到基础位会产生新的位模式,因此会产生不相等的双精度。

正如Jon所说:

“如果你尝试添加一点 数字变为一个很大的数字 差别可能很小,以至于 最接近的结果与 原创。”

例如:

// True:
(Double.MAX_VALUE + Double.MIN_VALUE) == Double.MAX_VALUE
// False:
Double.longBitsToDouble(Double.doubleToLongBits(Double.MAX_VALUE) + 1) == Double.MAX_VALUE)
MIN_VALUE
是可表示的最小正双精度,但这并不意味着将其添加到任意双精度中会导致不相等的双精度


相反,将1添加到基础位会产生新的位模式,因此会产生不相等的双精度。

好的,让我们这样设想,坚持使用十进制数。假设您有一个浮点数类型,它允许您表示5个十进制数字,指数为0到3之间的数字,将结果乘以1、10、100或1000

所以最小的非零值只有1(即尾数=00001,指数=0)。最大值为9999000(尾数=99999,指数=3)

现在,如果将1添加到50000000,会发生什么?您不能表示50000001…500000000之后的下一个可表示数字是50001000。因此,如果您尝试将它们相加,结果将是与“真实”结果最接近的值-仍然是500000000。这就像将
Double.MIN\u值添加到一个大的
Double

我的版本(转换为位,递增,然后再转换回)就像是取50000000,分解成尾数和指数(m=50000,e=3),然后将其最小值递增到(m=50001,e=3),然后重新组合到50001000

你看到他们有什么不同吗


下面是一个具体的例子:

public class Test{
    public static void main(String[] args) {
        double before = 100000000000000d;
        double after = before + Double.MIN_VALUE;
        System.out.println(before == after);

        long bits = Double.doubleToLongBits(before);
        bits++;
        double afterBits = Double.longBitsToDouble(bits);
        System.out.println(before == afterBits);
        System.out.println(afterBits - before);
    }
}
这将大量尝试这两种方法。输出为:

true
false
0.015625
通过输出,这意味着:

  • 添加
    Double.MIN\u值
    没有任何效果
  • 增加位确实有效果
  • afterBits
    before
    之间的差值为0.015625,远大于
    Double.MIN\u值。难怪简单的添加没有效果
    
      好吧,让我们这样想象,坚持十进制数字。假设您有一个浮点数类型,它允许您表示5个十进制数字,指数为0到3之间的数字,将结果乘以1、10、100或1000

      所以最小的非零值只有1(即尾数=00001,指数=0)。最大值为9999000(尾数=99999,指数=3)

      现在,如果将1添加到50000000,会发生什么?您不能表示50000001…500000000之后的下一个可表示数字是50001000。因此,如果您尝试将它们相加,结果将是与“真实”结果最接近的值-仍然是500000000。这就像将
      Double.MIN\u值添加到一个大的
      Double

      我的版本(转换为位,递增,然后再转换回)就像是取50000000,分解成尾数和指数(m=50000,e=3),然后将其最小值递增到(m=50001,e=3),然后重新组合到50001000

      你看到他们有什么不同吗


      下面是一个具体的例子:

      public class Test{
          public static void main(String[] args) {
              double before = 100000000000000d;
              double after = before + Double.MIN_VALUE;
              System.out.println(before == after);
      
              long bits = Double.doubleToLongBits(before);
              bits++;
              double afterBits = Double.longBitsToDouble(bits);
              System.out.println(before == afterBits);
              System.out.println(afterBits - before);
          }
      }
      
      这将大量尝试这两种方法。输出为:

      true
      false
      0.015625
      
      通过输出,这意味着:

      • 添加
        Double.MIN\u值
        没有任何效果
      • 增加位确实有效果
      • afterBits
        before
        之间的差值为0.015625,远大于
        Double.MIN\u值。难怪这个简单的加法器