8

我想将 Haskell 浮点数转换为包含标准 IEEE 格式的浮点数的 32 位十六进制表示的字符串。我似乎找不到可以为我做这件事的包。有人知道吗?

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

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

4

4 回答 4

6

float-ieee 包是纯 Haskell-98,但 CPU 非常密集。如果您需要多次执行此操作,并且不介意特定于 GHC,那么您可以使用这样的代码,它将 a 的 IEEE 表示提取Double为 a 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

于 2010-02-16T05:32:31.457 回答
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
于 2010-02-16T00:21:53.587 回答
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 编译器一起工作,但对底层实现有一点依赖,所以很难保证。

于 2010-09-21T07:33:41.533 回答
1

我认为您不小心解码了 aDouble而不是 a Float。这就是为什么它似乎不适合。

于 2010-02-16T00:30:45.380 回答