2010-02-15 60 views
7

我想將Haskell Float轉換爲包含標準IEEE格式的浮點數的32位十六進制表示形式的字符串。我似乎無法找到一個能爲我做到這一點的軟件包。有人知道嗎?Haskell中浮點數的十六進制表示

我注意到,GHC.Float提供了一個函數來將Float分解爲它的帶符號的基和指數(decodeFloat),但是它分別爲基和指數提供了一個14和8位的十六進制數,佔用了大於32位。這似乎沒有幫助。

如果有更簡單的方法可以做到這一點,我沒有看到,請讓我知道。

+0

在Haskell中漂浮只有4個字節(32位)?這似乎不足以給你一個14位數的尾數和一個8位指數。 – pavium 2010-02-16 00:12:47

回答

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 
+0

這將「Pi」打印爲「@I」。這是一個不同的十六進制表示? – Jeremy 2010-03-04 00:31:39

+0

它不是十六進制。它只是一個字節串。你需要一個不同的庫/函數以十六進制打印字節串值。 – sclv 2010-09-21 12:51:10

1

我想你不小心解碼的Double而不是Float的。這就是爲什麼它似乎不適合。

5

float-ieee軟件包是純粹的Haskell-98,但CPU密集型。如果你要需要做很多次了,不介意被GHC具體,那麼你用這樣的代碼,它提取的DoubleWord64的IEEE表示:

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) 

你可以代碼對於FloatWord32類似的東西。

+0

從技術上講,這也假定'雙'在IEEE格式的硬件中表示,但這可能是GHC運行的每個平臺的情況。您還需要了解與「Word64」的機器表示有關的排序問題。 – 2010-09-23 12:49:33

2

有幾種不同的方式可以做到這一點,這取決於你的口味。使用像唐提到的庫可能是最好的選擇,否則你可以嘗試一些沿着這些線:

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編譯器一起工作,但是對底層實現依賴性很小,很難保證。