我注意到 Haskell(来自 Windows 上 Haskell 平台的 ghci 7.10.2)翻转了 QNAN 上的标志 (0/0 :: Double)
从我在 C++ 中看到的(测试 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 未定义语义的一部分吗? IE。 (0/0) 意味着 ghc 可以使用他们想要的任何 NaN 模式?那么我们在 Haskell 中是否有一种精确的方法来在 float 中指定 QNAN 或 SNAN 而无需求助于特殊的 IEEE 库 4 ?我正在为一个硬件编写一个汇编程序,该硬件可能对它的 NaN 风格很挑剔。
我会被
unsafeCoerce
灼伤吗? ?我在 Haskell 中没有简单的方法来将 float 转换为位并返回。
引用资料:
- MSVS 2013。C++
std::numeric_limits<double>::quiet_NaN()
从给出 0x7ff8000000000000
.还在 cygwin gcc 4.9.2 上测试 - std::numeric_limits::quiet_NaN .声明符号位的任何含义都是实现定义的。 Haskell 对此有类似的规则吗?
- Perl semantics与MSV C++一致
- 可能是 Haskell library IEEE
- 稍微相关question使用相同的
unsafeCoerce
胡说八道,我退缩了。
最佳答案
您对 NaN 的要求过高。根据 IEEE 标准,NaN 的符号位可以是任何东西。因此编译器、处理器或浮点库可以自由地做出他们想要的任何选择,并且您将在不同的编译器、处理器和库上得到不同的结果。
特别是对于这样的程序,常量折叠可能意味着操作由编译器而不是在目标环境中执行,具体取决于编译器的运行方式。编译器可能会使用 native 浮点指令,也可能会改用 GMP 或 MPFR 之类的指令。这并不少见。由于 IEEE 标准对符号位只字不提,因此对于不同的实现,您最终会得到不同的值。如果您能证明当您打开或关闭优化时这些值发生了变化,我不会感到完全惊讶,那不包括 -ffast-math
之类的东西。
作为优化的一个例子,编译器知道您正在计算一个NaN
,并且它可能决定不在之后翻转符号位。这一切都是通过不断传播发生的。另一个编译器不做那种分析,所以它发出一条指令来翻转符号位,而制造你的处理器的人不会让这个操作对 NaN 有不同的行为。
简而言之,不要试图理解 NaN 上的符号位。
你到底想在这里完成什么?
关于c++ - Haskell 将 (0/0) 设置为 qnan,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34191455/