Haskell: 从二进制文件中读取 [Double]

Haskell: read [Double] from binary file

我有一个包含二进制数据的文件(更准确地说,它是一个 npy 文件 = header 数据 + 原始二进制数据)。此数据([0.1, 0.2, 0.3, 0.4] 用于测试)可以通过 C++ 中的此代码成功读取(已跳过):

int word_size = 8;
double *data;
arr = new char[size*word_size];
size_t nread = fread(arr, word_size, size, file);
if(nread != size)
    *data = reinterpret_cast<double *>(arr);

我正在尝试在 Haskell 中实现它:

data Header = Header {
    {- other fields -}
    npyData         :: [Double]
    } deriving (Show)

getNpyData = do
    empty <- isEmpty
    if empty
        then return []
        else do 
            v <- getWord64be
            rest <- getNpyData
            return (fromIntegral v : rest)

npyHeader :: Get Header
npyHeader = do
    {-other fields -}
    npyData <- getNpyData
    return Header {
        {- other fields -}
        npyData=npyData
    }


main = do
    file <- openBinaryFile "test.npy" ReadMode
    input <- BL.hGetContents file
    let npyParsedData = runGet npyHeader input
    print $ npyData npyParsedData

这给我的 npyData 结果不正确(其他变量没问题):

[1.1140104038263667e19,1.114010403826367e19,3.6893488147419515e18,1.1140104038263675e19]

谁能告诉我这段代码有什么问题吗?

您应该尝试 cereal(link) 中的 getFloat...getDouble... 函数。

您的代码正在执行的操作是读取 64 位整数值并将其转换为 Double。

不幸的是,什么应该起作用

     v <- get :: Double

没有,因为 Data.Binary 不使用双精度的 IEEE754 编码(它存储 decodeFloat 的结果)。因此,一个不错的选择是使用谷物包。至少在 GHC 中,我已经 unsafeCoerceWord64 上完成类似的任务。

    bitsToDouble :: Word64 -> Double
    bitsToDouble = unsafeCoerce

可能 cereal 是一种更安全的方法。