4

我正在尝试解析 Haskell 中的二进制文件格式(Apple 的二进制属性列表格式),该格式要求的一件事是将字节序列视为(a)无符号 1-、2- 或 4-字节整数;(b) 有符号的 8 字节整数;(c) 32 位float;(d) 64 位doubles。将字节序列转换为无符号整数很容易,即使处理有符号整数也不会很糟糕。但是对于有符号整数,尤其Floats 和Doubles,我真的不想自己实现逻辑。我已经能够在GHC.Primint2Float# :: Int# -> Float#中找到函数int2Double# :: Int# -> Double#,但这些似乎并不理想(我不是特别想使用未装箱的类型)。我希望有一些方法可以从 a[Word8]Word32s/ Word64s 投射。是否有任何 type Word32 -> FloatWord64 -> DoubleWord64 -> Int64或类似的函数?

4

2 回答 2

5

如果您不知道,fromIntegral可以很好地转换积分。此外,二进制包和相关的 data-binary-ieee754包非常适用于您的问题。

λ> :set -XOverloadedStrings
λ> import           Data.Binary.Get       (runGet)
λ> import qualified Data.Binary.IEEE754   as I
λ> runGet I.getFloat32le "\STX\SOH\SOH\SOH"
2.369428e-38
λ> runGet I.getFloat32le "\STX\SOH\SOH\SOHtrailing characters are ignored"
2.369428e-38
λ> runGet I.getFloat32le "\STX\SOH\SOH" -- remember to use `catch`:
*** Exception: Data.Binary.Get.runGet at position 0: not enough bytes
CallStack (from HasCallStack):
  error, called at libraries/binary/src/Data/Binary/Get.hs:351:5 in binary-0.8.5.1:Data.Binary.Get
于 2011-01-10T04:10:20.093 回答
1

Unsafe.Coerce.unsafeCoerce可以在类型之间进行转换,例如 C++ 的reinterpret_cast<>. 谨慎使用。

否则,您可以使用RealFloat.

bitsAsIEEE754 :: (Bits a, Integral a, RealFloat b) => a -> b
bitsAsIEEE754 word =
    assert (floatRadix float == 2) $
    assert (bitSize word == 1 + es + ms) $
    assert (1 `shiftL` es == maxE - minE + 3) $
    float
  where
    ms = floatDigits float - 1
    (minE, maxE) = floatRange float
    es = length $ takeWhile (< maxE - minE + 2) $ iterate (* 2) 1
    sgn = if testBit word (ms + es) then negate else id
    e = fromIntegral $ word `shiftR` ms .&. (1 `shiftL` es - 1)
    nor = if e == 0 then id else flip setBit ms
    m = sgn . toInteger . nor $ word .&. (1 `shiftL` ms - 1)
    float = encodeFloat m $ max minE (e + minE - 1) - ms - 1

至少在我的 GHC 中,似乎无法创建-0NaN使用encodeFloat,但其他一切都应该工作。

于 2011-01-10T03:58:43.647 回答