Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IEEE floating point signalling NaN (sNaN) in Haskell

Is there any way to define signaling NaN in Haskell? I found two approaches to deal with NaNs:

1) use 0/0, which produces quite nan

2) package Data.Number.Transfinite, which has no signaling NaNs too.

PS Is there any way to put Word64 bit by bit into Double without writing C library?

like image 960
Aleksandr Pakhomov Avatar asked Jan 24 '14 23:01

Aleksandr Pakhomov


1 Answers

I have found one non-portable way:

{-# LANGUAGE ForeignFunctionInterface #-}
import Data.Word (Word64, Word32)
import Unsafe.Coerce
import Foreign
import Foreign.C.Types
foreign import ccall "fenv.h feenableexcept" -- GNU extension
    enableexcept :: CInt -> IO ()

class HasNAN a where
    signalingNaN :: a
    quietNaN :: a

instance HasNAN Double where
    signalingNaN = unsafeCoerce (0x7ff4000000000000::Word64)
    quietNaN = unsafeCoerce (0x7ff8000000000000::Word64)

instance HasNAN Float where
    signalingNaN = unsafeCoerce (0x7fa00000::Word32)
    quietNaN = unsafeCoerce (0x7fc00000::Word32)

main = do
    enableexcept 1 -- FE_INVALID in my system
    print $ show $ 1 + (quietNaN :: Float) -- works
    print $ show $ 1 + (signalingNaN :: Float) -- fails

which perfectly fails. It turned out that FPU exceptions are a bad idea for Haskell. They are disabled by default for a good reason. They are OK if you debug C/C++/something else in gdb. I don't want to debug Haskell core dumps due to its non-imperative nature. Enabling FE_INVALID exceptions causes 0/0 and add to NaNs in Data.Number.Transfinite and GHC.Real to crash. But 0/0 calculated before enableexcept doesn't produce exceptions in addition.

I will use some simple errors check in my task. I need sNaN in just one place.

like image 60
Aleksandr Pakhomov Avatar answered Oct 22 '22 00:10

Aleksandr Pakhomov