我正在尝试解析 Haskell 中的二进制文件格式(Apple 的二进制属性列表格式),该格式要求的一件事是将字节序列视为(a)无符号 1-、2- 或 4-字节整数;(b) 有符号的 8 字节整数;(c) 32 位float
;(d) 64 位double
s。将字节序列转换为无符号整数很容易,即使处理有符号整数也不会很糟糕。但是对于有符号整数,尤其是Float
s 和Double
s,我真的不想自己实现逻辑。我已经能够在GHC.Primint2Float# :: Int# -> Float#
中找到函数int2Double# :: Int# -> Double#
,但这些似乎并不理想(我不是特别想使用未装箱的类型)。我希望有一些方法可以从 a[Word8]
或Word32
s/ Word64
s 投射。是否有任何 type Word32 -> Float
、Word64 -> Double
、Word64 -> Int64
或类似的函数?
问问题
2788 次
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<>
. 谨慎使用。
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 中,似乎无法创建-0
和NaN
使用encodeFloat
,但其他一切都应该工作。
于 2011-01-10T03:58:43.647 回答