这两种方法到Java中最小的Double值是否相等? [英] Are these two approaches to the smallest Double values in Java equivalent?

查看:161
本文介绍了这两种方法到Java中最小的Double值是否相等?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

替代措辞:何时将Double.MIN_VALUE添加到Java 不是中的double将导致不同的Double值? (见下面的Jon Skeet的评论)

Jon Skeet 理查德

Jon的回答使用以下内容:

>

  double d = //您现有的值; 
long bits = Double.doubleToLongBits(d);
位++;
d = Double.longBitsToDouble();

理查兹回答提到JavaDoc for Double.MIN_VALUE


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

我的问题是,如何 Double.logBitsToDouble(0x1L)不同从Jon的位++;



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


添加
Double.MIN_VALUE到一个double值
并增加位模式
表示双倍。他们是
完全不同的操作,由于
浮点数
的存储方式。如果你试图把一个非常小的数字加到一个很大的数字b $ b上,那么这个差别可能就是这么小的
,最接近的结果就是原来的
。然而,对当前的
位模式加1,总是
将相应的浮动
点值改变为在该尺度下可见的最小可能值


我没有看到Jon用增加Double.MIN_VALUE的方法增加一个longbits ++的方法。他们什么时候会产生不同的结果?



我写了下面的代码来测试差异。也许有人可以提供更多/更好的样本双数或使用循环来找到一个数字,如果有差异。

$ pre $ d $ d $ = 3.14159269123456789; // sample double
long bits = Double.doubleToLongBits(d);
long bitsBefore = 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)与Double.doubleToLongBits(Double.MIN_VALUE)相同) ;


if(bitsDiff == bitsMinValue)
{
System.out.println(bits ++与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))与Double.doubleToLongBits(Double.MIN_VALUE)相同
bits ++与Double.MIN_VALUE $ b $相同地增加相同的数量使用doubleToLongBits / bits ++
位之前:4614256656636814345
位之后:4614256656636814346
位差异:1
位最小值:1
位小值:1


解决方案

好的,让我们用这种方式想象一下,坚持十进制数字。假设你有一个浮点小数点类型,它允许你表示5个十进制数字,以及一个介于0到3之间的数字,以1,10,100或1000倍数结果。



所以最小的非零值就是1(即尾数= 00001,指数= 0)。最大的值是99999000(尾数= 99999,指数= 3)。

现在,当你添加1到50000000时会发生什么?你不能表示50000001 ...在500000000是50001000之后的下一个可表示的数字。所以如果你试图将它们加在一起,结果只是最接近于真结果 - 仍然是500000000。例如将 Double.MIN_VALUE 添加到一个大的 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 + Double.MIN_VALUE;
System.out.println(before == after);

long bits = Double.doubleToLongBits(before);
位++;
double afterBits = Double.longBitsToDouble(bits);
System.out.println(before == afterBits);
System.out.println(afterBits - before);






这个方法使用了大量的方法。输出结果是:

pre $ true
false
0.015625
$ / code>


通过输出,这意味着:

$ ul

  • 添加 Double.MIN_VALUE 没有任何作用

  • 增加位有效

  • afterBits 之前的区别是0.015625, em>大于 Double.MIN_VALUE 。难怪简单加法没有效果!

    Alternative wording: When will adding Double.MIN_VALUE to a double in Java not result in a different Double value? (See Jon Skeet's comment below)

    This SO question about the minimum Double value in Java has some answers which seem to me to be equivalent. Jon Skeet's answer no doubt works but his explanation hasn't convinced me how it is different from Richard's answer.

    Jon's answer uses the following:

    double d = // your existing value;
    long bits = Double.doubleToLongBits(d);
    bits++;
    d = Double.longBitsToDouble();
    

    Richards answer mentions the JavaDoc for Double.MIN_VALUE

    A constant holding the smallest positive nonzero value of type double, 2-1074. It is equal to the hexadecimal floating-point literal 0x0.0000000000001P-1022 and also equal to Double.longBitsToDouble(0x1L).

    My question is, how is Double.logBitsToDouble(0x1L) different from Jon's bits++;?

    Jon's comment focuses on the basic floating point issue.

    There's a difference between adding Double.MIN_VALUE to a double value, and incrementing the bit pattern representing a double. They're entirely different operations, due to the way that floating point numbers are stored. If you try to add a very little number to a very big number, the difference may well be so small that the closest result is the same as the original. Adding 1 to the current bit pattern, however, will always change the corresponding floating point value, by the smallest possible value which is visible at that scale.

    I don't see any difference to Jon's approach of incrementing a long, "bits++", with adding Double.MIN_VALUE. When will they produce different results?

    I wrote the following code to test the differences. Maybe someone could provide more/better sample double numbers or use a loop to find a number where there is a difference.

        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);  
    

    OUTPUT:

    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
    

    解决方案

    Okay, let's imagine it this way, sticking with decimal numbers. Suppose you have a floating decimal point type which allows you to represent 5 decimal digits, and a number between 0 and 3 for the exponent, to multiple the result by 1, 10, 100 or 1000.

    So the smallest non-zero value is just 1 (i.e. mantissa=00001, exponent=0). The largest value is 99999000 (mantissa=99999, exponent=3).

    Now, what happens when you add 1 to 50000000? You can't represent 50000001...the next representable number after 500000000 is 50001000. So if you try to add them together, the result is just going to be the closest value to the "true" result - which is still 500000000. That's like adding Double.MIN_VALUE to a large double.

    My version (converting to bits, incrementing and then converting back) is like taking that 50000000, splitting into mantissa and exponent (m=50000, e=3) then incrementing it the smallest amount, to (m=50001, e=3) and then reassembling to 50001000.

    Do you see how they're different?


    Now here's a concrete example:

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

    This tries both approaches with a large number. The output is:

    true
    false
    0.015625
    

    Going through the output, that means:

    • Adding Double.MIN_VALUE didn't have any effect
    • Incrementing the bit did have an effect
    • The difference between afterBits and before is 0.015625, which is much bigger than Double.MIN_VALUE. No wonder the simple addition had no effect!

    这篇关于这两种方法到Java中最小的Double值是否相等?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆