我想将Haskell Float转换为包含标准IEEE格式的float的32位十六进制表示的String。我似乎找不到能为我做这件事的套餐。有人知道吗?
我注意到GHC.Float提供了一个函数来将Float分解为其带符号的基数和指数(decodeFloat),但这分别为基数和指数提供了14位和8位十六进制数,超过32位。这似乎没有帮助。
如果有一种更简单的方法可以做到这一点,我没有看到,请告诉我。
答案 0 :(得分:5)
float-ieee包是纯Haskell-98,但CPU密集型。如果你需要多次这样做,并且不介意GHC特定,那么你使用这样的代码,它将Double
的IEEE表示提取为Word64
:
import GHC.Prim
import GHC.Types
import GHC.Word
encodeIEEEDouble :: Double -> Word64
encodeIEEEDouble (D# x) = W64# (unsafeCoerce# x)
decodeIEEEDouble :: Word64 -> Double
decodeIEEEDouble (W64# x) = D# (unsafeCoerce# x)
您可以为Float
和Word32
编写类似的代码。
答案 1 :(得分:4)
Hackage上的float-ieee包怎么样? http://hackage.haskell.org/package/data-binary-ieee754
将打印一个32位ieee754字符串值,表示传入的浮点数。
import Data.Binary.Put
import Data.Binary.IEEE754
import qualified Data.ByteString.Lazy.Char8 as S
main = do
let s = runPut $ putFloat32be pi
S.putStrLn s
答案 2 :(得分:2)
根据您的口味,有几种不同的方法可以做到。使用Don提到的库可能是最好的选择,否则你可以尝试一下这些:
doubleToBytes :: Double -> [Int]
doubleToBytes d
= runST (do
arr <- newArray_ ((0::Int),7)
writeArray arr 0 d
arr <- castDoubleToWord8Array arr
i0 <- readArray arr 0
i1 <- readArray arr 1
i2 <- readArray arr 2
i3 <- readArray arr 3
i4 <- readArray arr 4
i5 <- readArray arr 5
i6 <- readArray arr 6
i7 <- readArray arr 7
return (map fromIntegral [i0,i1,i2,i3,i4,i5,i6,i7])
)
-- | Store to array and read out individual bytes of array
dToStr :: Double -> String
dToStr d
= let bs = doubleToBytes d
hex d' = case showHex d' "" of
[] -> error "dToStr: too few hex digits for float"
[x] -> ['0',x]
[x,y] -> [x,y]
_ -> error "dToStr: too many hex digits for float"
str = map toUpper $ concat . fixEndian . (map hex) $ bs
in "0x" ++ str
-- | Create pointer to Double and cast pointer to Word64, then read out
dToStr2 :: Double -> IO String
dToStr2 f = do
fptr <- newStablePtr f
let pptr = castStablePtrToPtr fptr
let wptr = (castPtrToStablePtr pptr)::(StablePtr Word64)
w <- deRefStablePtr wptr
let s = showHex w ""
return ("0x" ++ (map toUpper s))
-- | Use GHC specific primitive operations
dToStr3 :: Double -> String
dToStr3 (D# f) = "0x" ++ (map toUpper $ showHex w "")
where w = W64# (unsafeCoerce# f)
三种不同的方式。最后是GHC特定的。其他两个可能与其他Haskell编译器一起工作,但是在底层实现上有点依赖,所以很难保证。
答案 3 :(得分:1)
我认为你不小心解码了Double
而不是Float
。这就是它似乎不合适的原因。