Personal tools

Examples/Read Double

From HaskellWiki

Jump to: navigation, search


Efficiently read to and from a CDouble.

{-# OPTIONS -ffi #-}
 
import Data.ByteString.Lazy.Char8 (ByteString)
import qualified Data.ByteString.Char8      as B
import qualified Data.ByteString.Base       as B
import qualified Data.ByteString.Lazy.Char8 as L
import Foreign
import Foreign.C.Types
import System.IO.Unsafe
 
------------------------------------------------------------------------
 
--
-- read a Double from a lazy ByteString
-- 'read' should be a pure operation, right??
--
readDouble :: ByteString -> Double
readDouble ls = unsafePerformIO $ B.useAsCString s $ \cstr ->
    realToFrac `fmap` c_strtod cstr nullPtr
  where
    s = B.concat . L.toChunks $ ls
 
foreign import ccall unsafe "static stdlib.h strtod" c_strtod
    :: Ptr CChar -> Ptr (Ptr CChar) -> IO CDouble
 
------------------------------------------------------------------------
--
-- show a Double into a lazy bytestring
--
 
showDouble :: Double -> ByteString
showDouble d = L.fromChunks . return . unsafePerformIO . B.createAndTrim lim $  \p ->
    B.useAsCString fmt $ \cfmt -> do
        n <- c_printf_double (castPtr p) (fromIntegral lim) cfmt (realToFrac d)
        return (min lim (fromIntegral n)) -- snprintf might truncate
  where
    lim = 100 -- n.b.
    fmt = B.pack "%f"
 
foreign import ccall unsafe "static stdio.h snprintf" 
    c_printf_double :: Ptr CChar -> CSize -> Ptr CChar -> CDouble -> IO CInt
 
------------------------------------------------------------------------
 
--
-- And sum lazy bytestring doubles read from stdin
-- Using packed writes to output as well.
--
main = do L.interact $ showDouble . sum . map readDouble . L.lines
          putStrLn ""

Calls into C.