flat-0.4: src/Data/FloatCast.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Trustworthy ,NoMonomorphismRestriction#-}
{- | Primitives to convert between Float\/Double and Word32\/Word64.
Code copied from <https://hackage.haskell.org/package/binary binary>.
Based on: <http://hackage.haskell.org/package/reinterpret-cast-0.1.0/docs/src/Data-ReinterpretCast-Internal-ImplArray.html>..
Implements casting via a 1-element STUArray, as described in <http://stackoverflow.com/a/7002812/263061>.
-}
module Data.FloatCast
( floatToWord
, wordToFloat
, doubleToWord
, wordToDouble
, runST
, cast
)
where
import Data.Word ( Word32
, Word64
)
import Data.Array.ST ( newArray
, readArray
, MArray
, STUArray
)
import Data.Array.Unsafe ( castSTUArray )
import GHC.ST ( runST
, ST
)
-- import Flat.Endian
-- | Reinterpret-casts a `Word32` to a `Float`.
{-|
prop> \f -> wordToFloat (floatToWord f ) == f
>>> floatToWord (-0.15625)
3189768192
>>> wordToFloat 3189768192
-0.15625
>>> floatToWord (-5.828125) == 0xC0BA8000
True
-}
wordToFloat :: Word32 -> Float
wordToFloat x = runST (cast x)
{-# INLINE wordToFloat #-}
-- | Reinterpret-casts a `Float` to a `Word32`.
floatToWord :: Float -> Word32
floatToWord x = runST (cast x)
{-# INLINE floatToWord #-}
-- $setup
-- >>> import Numeric (showHex)
-- >>> import Data.Word
-- | Reinterpret-casts a `Double` to a `Word64`.
{-|
prop> \f -> wordToDouble (doubleToWord f ) == f
>>> showHex (doubleToWord 1.0000000000000004) ""
"3ff0000000000002"
>>> doubleToWord 1.0000000000000004 == 0x3FF0000000000002
True
>>> showHex (doubleToWord (-0.15625)) ""
"bfc4000000000000"
>>> wordToDouble 0xbfc4000000000000
-0.15625
-}
{-# INLINE doubleToWord #-}
doubleToWord :: Double -> Word64
doubleToWord x = runST (cast x)
-- doubleToWord x = fix64 $ runST (cast x)
-- | Reinterpret-casts a `Word64` to a `Double`.
{-# INLINE wordToDouble #-}
wordToDouble :: Word64 -> Double
wordToDouble x = runST (cast x)
-- wordToDouble x = runST (cast $ fix64 x)
{- |
>>> runST (cast (0xF0F1F2F3F4F5F6F7::Word64)) == (0xF0F1F2F3F4F5F6F7::Word64)
True
-}
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
{-# INLINE cast #-}
-- Required for older versions of ghcjs
-- #ifdef ghcjs_HOST_OS
-- doubleToWord x = (`rotateR` 32) $ runST (cast x)
-- #else
-- doubleToWord x = runST (cast x)
-- #endif
-- #ifdef ghcjs_HOST_OS
-- wordToDouble x = runST (cast $ x `rotateR` 32)
-- #else
-- wordToDouble x = runST (cast x)
-- #endif