2010-12-20 12 views
7

を追加インストールすることなく、の数値を効率的に読み取る方法をお探しです。 Data.ByteString.Lazy.Char8.readIntは整数のトリックを行うようです。私はByteStringは今readDoubleメソッドを持っていることを読んだが、私はimport Data.ByteString.Lex.Lazy.Double (readDouble)を書くとき、コンパイラは文句:Haskellで効率的に数値を読み取る

 
    Main.hs:4:7: 
     Could not find module `Data.ByteString.Lex.Lazy.Double': 
      locations searched: 
      Data/ByteString/Lex/Lazy/Double.hs 
      Data/ByteString/Lex/Lazy/Double.lhs 

マイバイト文字列パッケージのバージョンは0.9.1.5です。

私は何か間違っていますか?または、問題のためのよりよい解決策があるかもしれませんか?ありがとう。

アップデート:OK、readDoubleは、デフォルトではインストールされていないbytestring-lexerパッケージに含まれているようです。他のアイデア?

+1

ちょうどそのバイト文字列-レクサーパッケージをインストールします。 "cabal install bytestring-lexer" – sclv

+1

私のプログラムは私が制御できないサーバー上で動くので、私は追加のパッケージなしでやりたい。 – adamax

+0

@adamax:あなたの質問にその制限を加える価値があります。 –

答えて

3

私はクリティカルパス上のダブルスの解析でエラーが発生しまし唯一の時間は、私はこれを使用:

{-# LANGUAGE ForeignFunctionInterface #-} 
import qualified Data.ByteString.Char8 as B 
import Foreign.C.Types 
import Foreign.C.String 
import System.IO.Unsafe 

foreign import ccall unsafe "stdlib.h atof" c_atof :: CString -> IO CDouble 
unsafeReadDouble = unsafePerformIO . flip B.useAsCString c_atof 

をその時にバイト文字列にreadDoubleのように見えたものは、しかし、ありませんでした。それが現在の標準であれば、おそらくもっと良い解決策になるだろう。

+0

ありがとう!私はいくつかの実験をしました。物事を簡単にするために、私はatofの代わりにatoiを使い、それを通常のショー機能と私の素朴な実装(iread)と比較しました。 FFIは完全に拍手をかけるが、それはireadに対して約20%の損失をもたらす。おそらく、CStringへの変換によって引き起こされるオーバーヘッドがあります – adamax

2

ここで私が思いついたのです。

私はJBによって提供される機能を使用し、私はbytestring-lexing(thanks、sclv!)のソースコードから学んだ2つのトリックを追加しました。最初の関数は次のとおりです。

strict = SB.concat . LB.toChunks

これは、遅延レイアウを非レイジーに効率的に変換します。

第2のトリックは、unsafePerformIOのより効率的な変種である機能Data.ByteString.Internal.inlinePerformIOです。


{-# LANGUAGE ForeignFunctionInterface #-} 

import qualified Data.ByteString.Lazy.Char8 as LB 
import qualified Data.ByteString as SB 
import Data.ByteString.Internal (inlinePerformIO) 
import Foreign.C.String (CString) 
import Foreign.C (CDouble) 
import Data.Maybe (fromJust) 

foreign import ccall unsafe "stdlib.h atof" c_atof :: CString -> IO Double 
unsafeReadDouble = inlinePerformIO . flip SB.useAsCString c_atof 
{-# INLINE unsafeReadDouble #-} 
readDouble = unsafeReadDouble . SB.concat . LB.toChunks 
readInt = fst . fromJust . LB.readInt 

そして、入力中のすべての数字の合計を計算するサンプルプログラム:

 
main = LB.getContents >>= (print . sum . map readDouble . LB.lines) 
It processes an 11Mb file (1M numbers) in about 0.5 seconds

I also found several links , where a much more efficient version of readIntが議論されている。ここ

はかなり速い番号の読み取りを可能にする完全なコードです。おそらく、同じ考え方に基づいてreadDoubleを構築することができます。しかし、私は今のところ私の現在のバージョンに固執すると思います。

5

別の解決策:bytestring-lexingパッケージをインストールし、readDoubleを使用してください。これは最適化されています。

cabal install bytestring-lexing 

パッケージには、浮動小数点リテラルのためoptimized parsing functionsを提供しています。

readDouble :: ByteString -> Maybe (Double, ByteString)   
関連する問題