Haskell将(0/0)设置为qnan

Haskell sets (0/0) as qnan

本文关键字:设置 qnan Haskell      更新时间:2023-10-16

我注意到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 未定义语义的一部分吗? 即(0/0(意味着ghc可以使用他们想要的任何NaN模式? 那么,在Haskell中,我们是否有一种精确的方法,可以在浮点中指定QNAN或SNAN,而无需诉诸特殊的IEEE库4? 我正在为一个硬件编写一个汇编程序,它可能对它的 NaN 口味挑剔。

  • 我被unsafeCoerce烧伤了吗? 我在 Haskell 中没有简单的方法从浮点数转换为位并返回。

引用:

  1. MSVS 2013.来自<限制>的C++ std::numeric_limits<double>::quiet_NaN()给出了0x7ff8000000000000. 也在cygwin gcc 4.9.2上进行了测试
  2. 标准::numeric_limits::quiet_NaN。 声明符号位的任何含义都是实现定义的。 Haskell对此有类似的规定吗?
  3. Perl 语义与 MSV C++一致
  4. 可能的 IEEE Haskell库
  5. 稍微相关的问题使用了我退回的相同的unsafeCoerce废话。

你对 NaN 的要求太多了。 根据IEEE标准,NaN上的符号位可以是任何东西。 因此,编译器、处理器或浮点库可以自由地做出它们想要的任何选择,您将在不同的编译器、处理器和库上获得不同的结果。

特别是,对于这样的程序,常量折叠可能意味着操作由编译器执行,而不是在目标环境中执行,具体取决于编译器的运行方式。 编译器可以使用本机浮点指令,也可以使用 GMP 或 MPFR 之类的指令。 这种情况并不少见。 由于IEEE标准没有提到符号位,因此对于不同的实现,您最终会得到不同的值。 如果您可以证明在打开或关闭优化时值会发生变化,我不会完全感到惊讶,这不包括-ffast-math之类的东西。

作为优化的一个例子,编译器知道您正在计算NaN,并且也许它决定之后不费心翻转符号位。 这一切都是通过不断传播来实现的。 另一个编译器不做这种分析,所以它会发出一条指令来翻转符号位,而制造处理器的人不会让该操作对 NaN 的行为有所不同。

简而言之,不要试图理解 NaN 上的符号位。

你到底想在这里完成什么?