{-# LANGUAGE FlexibleContexts #-} module Language.Wasm.FloatUtils ( wordToFloat, floatToWord, wordToDouble, doubleToWord, makeNaN, doubleToFloat ) where import Data.Word (Word32, Word64) import Data.Bits ((.|.), (.&.), shiftR) import Data.Array.ST (newArray, readArray, MArray, STUArray) import Data.Array.Unsafe (castSTUArray) import GHC.ST (runST, ST) -- brough from https://stackoverflow.com/questions/6976684/converting-ieee-754-floating-point-in-haskell-word32-64-to-and-from-haskell-floa wordToFloat :: Word32 -> Float wordToFloat x = runST (cast x) floatToWord :: Float -> Word32 floatToWord x = runST (cast x) wordToDouble :: Word64 -> Double wordToDouble x = runST (cast x) doubleToWord :: Double -> Word64 doubleToWord x = runST (cast x) {-# INLINE cast #-} cast :: (MArray (STUArray s) a (ST s), MArray (STUArray s) b (ST s)) => a -> ST s b cast x = newArray (0 :: Int, 0) x >>= castSTUArray >>= flip readArray 0 makeNaN :: Word64 -> Double makeNaN w = wordToDouble $ 0x7FF0000000000000 .|. (0x000FFFFFFFFFFFFF .&. w) doubleToFloat :: Double -> Float doubleToFloat d = let w = doubleToWord d in if 0x7FF0000000000000 == (w .&. 0x7FF0000000000000) && (w .&. 0x0007FFFFFFFFFFFF) /= 0 then wordToFloat $ fromIntegral $ ((0x8000000000000000 .&. w) `shiftR` 32) .|. 0x7F800000 .|. (0x7FFFFF .&. w) else realToFrac d