Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java NAN的位模式真的依赖于硬件吗?_Java_Floating Point_Nan_Ieee 754 - Fatal编程技术网

Java NAN的位模式真的依赖于硬件吗?

Java NAN的位模式真的依赖于硬件吗?,java,floating-point,nan,ieee-754,Java,Floating Point,Nan,Ieee 754,我在读Java语言规范中的浮点NaN值(我很无聊)。32位浮点具有以下位格式: seee eeee emmm mmmm mmmm mmmm mmmm mmmm s是符号位,e是指数位,m是尾数位。NaN值被编码为所有1的指数,尾数位不都是0(即+/-无穷大)。这意味着存在许多不同的可能NaN值(具有不同的s和m位值) 关于这一点,他说: IEEE 754允许其单浮点数格式和双浮点数格式具有多个不同的NaN值。当生成新的NaN时,每个硬件体系结构都会为NaN返回一个特定的位模式,而程序员也可以创

我在读Java语言规范中的浮点NaN值(我很无聊)。32位
浮点
具有以下位格式:

seee eeee emmm mmmm mmmm mmmm mmmm mmmm
s
是符号位,
e
是指数位,
m
是尾数位。NaN值被编码为所有1的指数,尾数位不都是0(即+/-无穷大)。这意味着存在许多不同的可能NaN值(具有不同的
s
m
位值)

关于这一点,他说:

IEEE 754允许其单浮点数格式和双浮点数格式具有多个不同的NaN值。当生成新的NaN时,每个硬件体系结构都会为NaN返回一个特定的位模式,而程序员也可以创建具有不同位模式的NaN来编码,例如,回顾性诊断信息

JLS中的文本似乎暗示,例如,
0.0/0.0
的结果具有与硬件相关的位模式,并且取决于该表达式是否作为编译时常量计算,它所依赖的硬件可能是编译Java程序所用的硬件或运行程序所用的硬件。如果这是真的,那么这一切看起来都很脆弱

我运行了以下测试:

System.out.println(Integer.toHexString(Float.floatToRawIntBits(0.0f/0.0f)));
System.out.println(Integer.toHexString(Float.floatToRawIntBits(Float.NaN)));
System.out.println(Long.toHexString(Double.doubleToRawLongBits(0.0d/0.0d)));
System.out.println(Long.toHexString(Double.doubleToRawLongBits(Double.NaN)));
我的机器上的输出是:

7fc00000
7fc00000
7ff8000000000000
7ff8000000000000
输出没有显示超出预期的内容。指数位都是1。尾数的高位也是1,对于NaN,这显然表示“安静的NaN”,而不是“信号NaN”()。符号位和尾数的其余位为0。输出还表明,在我的机器上生成的nan与Float和Double类的常量nan之间没有区别

我的问题是,无论编译器或虚拟机的CPU是多少,Java都能保证输出,还是真的无法预测?JLS对此很神秘

如果该输出保证为
0.0/0.0
,是否有任何生成具有其他(可能依赖于硬件的?)位模式的NAN的算术方法?(我知道
intBitsToFloat
/
longBitsToDouble
可以对其他NaN进行编码,但我想知道正常算术是否可以产生其他值。)



接下来的一点是:我注意到并指定了它们的精确位模式,但在源代码(,)中,它们是由
0.0/0.0
生成的。如果这种划分的结果确实依赖于编译器的硬件,那么在规范或实现中似乎存在缺陷。

我在这里读取JLS的方式是,NaN的确切位值取决于谁/什么制造了它,因为JVM没有制造它,所以不要问他们。您还可以询问他们“错误代码4”字符串的含义

硬件产生不同的位模式,表示不同类型的NaN。不幸的是,不同种类的硬件为相同种类的NaN产生不同的位模式。幸运的是,有一个标准模式,Java可以使用它来至少判断它是某种NaN

就像Java看了看“错误代码4”字符串,然后说,“我们不知道‘代码4’在您的硬件上是什么意思,但该字符串中有‘错误’一词,所以我们认为这是一个错误。”

JLS试图让您有机会自己解决问题:

“然而,Java SE平台的1.3版引入了一些方法,使程序员能够区分NaN值:
Float.floatorawintbits
Double.doubleToRawLongBits
方法。感兴趣的读者可参考
Float
Double
类的规范以了解更多信息。”

这看起来像是C++代码> RealTytCase<代码>。它是java给你一个机会来分析你自己的NI,以防你碰巧知道它的信号是如何编码的。如果你想跟踪硬件规格,那么你可以预测哪些不同的事件应该产生哪种NN位模式,你可以自由地做,但是你在U的外部。JVM本来是要给我们的,所以我们可以期待它会随着硬件的不同而变化

当测试一个数字是否为NaN时,我们会检查它是否等于它自己,因为它是唯一一个不等于NaN的数字。这并不是说位不同。在比较位之前,JVM会测试表示它为NaN的许多位模式。如果它是这些模式中的任何一种,那么它会报告它不相等,即使两个操作数的位是r所有的人都是一样的(即使他们不同)

早在1964年,当美国最高法院法官Stewart被要求给出色情的准确定义时,他有一句名言:“我一看到就知道了”。我认为Java对NaN的也做了同样的事情。Java不能告诉你任何“信号”的东西“NaN可能在发信号,因为它不知道信号是如何编码的。但它可以查看位并判断它是某种NaN,因为该模式遵循一个标准

如果您碰巧在硬件上使用统一的位对所有NaN进行编码,您将永远无法证明Java正在做任何事情来使NaN具有统一的位。再一次,我读JLS的方式,他们直截了当地说你在这里是靠自己的

我能理解为什么这感觉不好。它是片状的。这不是Java的错。我想说的是,一些有进取心的硬件制造商提出了非常有表现力的位模式,但他们未能将其作为一种标准广泛采用,以至于Java可以依赖它。这才是不可靠的。我们保留了所有这些位,用于表示我们有什么类型的NaN,而不能使用它们,因为我们不同意它们的含义。让Java在硬件使NaN获得统一的价值后将其击败,只会破坏这些信息,损害性能,唯一的回报是看起来不那么脆弱。考虑到这种情况,我很高兴
public class Test {
  public static void main(String[] arg) {
    double myNaN = Double.longBitsToDouble(0x7ff1234512345678L);
    System.out.println(Double.isNaN(myNaN));
    System.out.println(Long.toHexString(Double.doubleToRawLongBits(myNaN)));
    final double zeroDivNaN = 0.0 / 0.0;
    System.out.println(Double.isNaN(zeroDivNaN));
    System.out
        .println(Long.toHexString(Double.doubleToRawLongBits(zeroDivNaN)));
  }
}
true
7ff1234512345678
true
7ff8000000000000
- x86:     
   quiet:      Sign=0  Exp=0x7ff  Frac=0x80000
   signalling: Sign=0  Exp=0x7ff  Frac=0x40000
- PA-RISC:               
   quiet:      Sign=0  Exp=0x7ff  Frac=0x40000
   signalling: Sign=0  Exp=0x7ff  Frac=0x80000
- Power:
   quiet:      Sign=0  Exp=0x7ff  Frac=0x80000
   signalling: Sign=0  Exp=0x7ff  Frac=0x5555555500055555
- Alpha:
   quiet:      Sign=0  Exp=0      Frac=0xfff8000000000000
   signalling: Sign=1  Exp=0x2aa  Frac=0x7ff5555500055555
public static void main(String []args) {
    Double tentative1 = 0d/0d;
    Double tentative2 = Math.sqrt(-1d);
    
    System.out.println(tentative1);
    System.out.println(tentative2);
    
    System.out.println(Long.toHexString(Double.doubleToRawLongBits(tentative1)));
    System.out.println(Long.toHexString(Double.doubleToRawLongBits(tentative2)));
    
    System.out.println(tentative1 == tentative2);
    System.out.println(tentative1.equals(tentative2));
}