这两种方法在Java中是等效的吗?
备选措辞:在Java中,将Double.MIN_值添加到Double会导致不同的Double值吗?(见下面Jon Skeet的评论) 关于Java中最小双精度值的问题有一些答案,在我看来是等价的毫无疑问,这是可行的,但他的解释并没有让我相信这和他的解释有什么不同 Jon的回答使用了以下内容:这两种方法在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
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值。难怪这个简单的加法器