2015-01-13 5 views
0

У меня есть файл с двоичными данными (точнее, это npy file = данные заголовка + необработанные двоичные данные). Эти данные ([0,1, 0,2, 0,3, 0,4] для испытаний) могут быть успешно прочитанные этим кодом в C++ (пропущено):Haskell: прочитайте [Double] из двоичного файла

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] 

Может кто-нибудь сказать мне, что это неправильно в этом коде?

+0

Я просто наткнулся на эту статью [(link)] (http://ruhaskell.org/posts/utils/2015/01/15/npy-parsing.html) на разбор файлов npy в Haskell. Это на русском языке, но Google translate, похоже, делает достойную работу. – ErikR

+0

Thx, но это моя статья, частично основанная на этом вопросе =) – erthalion

+0

Это слишком смешно! – ErikR

ответ

2

Вы должны попробовать getFloat... и getDouble... функции от cereal пакета (link).

Что делает ваш код, так это чтение 64-битного целочисленного значения и преобразование, которое делает Double.

1

К сожалению, то, что должно работать

 v <- get :: Double 

не так Data.Binary не использует кодировку IEEE754 двойников (она сохраняет результат decodeFloat). Следовательно, хороший выбор заключается в использовании пакета зерновых. По крайней мере, в GHC я получил unsafeCoerce на Word64 для работы над аналогичными задачами.

bitsToDouble :: Word64 -> Double 
    bitsToDouble = unsafeCoerce 

Вероятно cereal является более безопасным способом сделать это.