Haskell中浮点数的十六进制表示

时间:2010-02-15 23:42:50

标签: haskell floating-point hex ieee-754

我想将Haskell Float转换为包含标准IEEE格式的float的32位十六进制表示的String。我似乎找不到能为我做这件事的套餐。有人知道吗?

我注意到GHC.Float提供了一个函数来将Float分解为其带符号的基数和指数(decodeFloat),但这分别为基数和指数提供了14位和8位十六进制数,超过32位。这似乎没有帮助。

如果有一种更简单的方法可以做到这一点,我没有看到,请告诉我。

4 个答案:

答案 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)

您可以为FloatWord32编写类似的代码。

答案 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。这就是它似乎不合适的原因。