Haskell将(0/0)设置为qnan

时间:2015-12-10 00:09:29

标签: c++ haskell floating-point ieee-754

我注意到Haskell(来自Windows上的Haskell平台的ghci 7.10.2)翻转了我在C ++中看到的QNAN (0/0 :: Double)上的标志(测试了MSVS C ++ 2013和cygwin gcc 4.9.2)。 Haskell为(0/0)生成位模式0xfff8000000000000( - (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中没有 easy 方式从float转换为bit和back。

参考文献:

  1. MSVS 2013.来自&lt; limits&gt;的C ++ std::numeric_limits<double>::quiet_NaN()给出0x7ff8000000000000。也在cygwin gcc 4.9.2
  2. 上进行了测试
  3. std::numeric_limits::quiet_NaN。表示符号位的任何含义是实现定义的状态。 Haskell对此有类似的规则吗?
  4. Perl semantics与MSV C ++一致
  5. IEEE
  6. 可能的Haskell library
  7. 略有关联的question使用的是与{I}相同的unsafeCoerce非感觉。

1 个答案:

答案 0 :(得分:5)

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

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

作为优化的示例,编译器知道您正在计算NaN,并且可能决定不打扰之后翻转符号位。这一切都通过不断传播发生。另一个编译器没有进行那种分析,因此它会发出翻转符号位的指令,而那些使你的处理器不能使该操作对NaN表现不同的人。

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

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