我注意到Haskell(来自Windows上的Haskell平台的ghci 7.10.2)(0/0 :: Double)
从我在C++中看到的QNAN标志上翻了一遍(测试了MSVS C++ 2013和cygwin gcc 4.9.2).Haskell 0xfff8000000000000
为(0/0)生成位模式(和 - (0/0)生成0x7ff8 ...).这是C++实现的后退似乎.
这是一个测试程序来说明:
import Data.Word import Unsafe.Coerce import Text.Printf dblToBits :: Double -> Word64 dblToBits = unsafeCoerce test :: Double -> IO () test d = putStrLn $ printf "%12f 0x%x" d (dblToBits d) go = do test (0/0) test (-(0/0)) test (1/0) test (-(1/0))
这给出了输出:
NaN 0xfff8000000000000 <- I expect 0x7F...? NaN 0x7ff8000000000000 <- I expect 0xFF...? Infinity 0x7ff0000000000000 -Infinity 0xfff0000000000000
请注意,无穷大可以正常运行,但NaN似乎翻了.
这是Haskell中NaN未定义语义的一部分吗?即(0/0)意味着ghc可以使用他们想要的任何NaN模式?那么我们在Haskell中有一个精确的方法是在浮点指定QNAN或SNAN而不依赖于特殊的IEEE库4吗?我正在为一块硬件编写一个汇编程序,可能对它的NaN味道很挑剔.
我被焚烧了unsafeCoerce
吗?我在Haskell中没有简单的方法可以将浮点数转换为位数和返回数.
参考文献:
MSVS 2013. std::numeric_limits
0x7ff8000000000000
.还在cygwin gcc 4.9.2上进行了测试
std :: numeric_limits :: quiet_NaN.表示符号位的任何含义是实现定义的状态.Haskell对此有类似的规则吗?
Perl语义与MSV C++一致
可能的IEEE Haskell 库
稍微相关的问题使用了unsafeCoerce
我回归的同样的无意义.
Dietrich Epp.. 5
你从你的NaN那里问了太多.根据IEEE标准,NaN上的符号位可以是任何东西.因此编译器,处理器或浮点库可以自由地做出他们想要的任何选择,并且您将在不同的编译器,处理器和库上获得不同的结果.
特别是,对于这样的程序,常量折叠可能意味着操作由编译器而不是在目标环境中执行,具体取决于编译器的运行方式.编译器可以使用本机浮点指令,也可以使用GMP或MPFR之类的东西.这并不罕见.由于IEEE标准对符号位没有任何说明,因此对于不同的实现,您将最终得到不同的值.如果您能够在开启或关闭优化时证明值已更改,并且不包括类似内容,那么我不会感到完全惊讶-ffast-math
.
作为优化的一个例子,编译器知道你正在计算a NaN
,并且可能决定不打扰之后翻转符号位.这一切都通过不断传播发生.另一个编译器不会进行这种分析,因此它会发出一个指令来翻转符号位,而那些制作处理器的人不会使该操作对NaN的行为有所不同.
简而言之,不要试图理解NaN上的符号位.
你究竟想在这里完成什么?
你从你的NaN那里问了太多.根据IEEE标准,NaN上的符号位可以是任何东西.因此编译器,处理器或浮点库可以自由地做出他们想要的任何选择,并且您将在不同的编译器,处理器和库上获得不同的结果.
特别是,对于这样的程序,常量折叠可能意味着操作由编译器而不是在目标环境中执行,具体取决于编译器的运行方式.编译器可以使用本机浮点指令,也可以使用GMP或MPFR之类的东西.这并不罕见.由于IEEE标准对符号位没有任何说明,因此对于不同的实现,您将最终得到不同的值.如果您能够在开启或关闭优化时证明值已更改,并且不包括类似内容,那么我不会感到完全惊讶-ffast-math
.
作为优化的一个例子,编译器知道你正在计算a NaN
,并且可能决定不打扰之后翻转符号位.这一切都通过不断传播发生.另一个编译器不会进行这种分析,因此它会发出一个指令来翻转符号位,而那些制作处理器的人不会使该操作对NaN的行为有所不同.
简而言之,不要试图理解NaN上的符号位.
你究竟想在这里完成什么?