packages feed

double-conversion 0.1.0.0 → 0.2.0.0

raw patch · 9 files changed

+318/−147 lines, 9 filesdep +bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring

API changes (from Hackage documentation)

- Data.Double.Conversion: toExponential :: Int -> Double -> Text
- Data.Double.Conversion: toFixed :: Int -> Double -> Text
- Data.Double.Conversion: toPrecision :: Int -> Double -> Text
- Data.Double.Conversion: toShortest :: Double -> Text
+ Data.Double.Conversion.ByteString: toExponential :: Int -> Double -> ByteString
+ Data.Double.Conversion.ByteString: toFixed :: Int -> Double -> ByteString
+ Data.Double.Conversion.ByteString: toPrecision :: Int -> Double -> ByteString
+ Data.Double.Conversion.ByteString: toShortest :: Double -> ByteString
+ Data.Double.Conversion.Text: toExponential :: Int -> Double -> Text
+ Data.Double.Conversion.Text: toFixed :: Int -> Double -> Text
+ Data.Double.Conversion.Text: toPrecision :: Int -> Double -> Text
+ Data.Double.Conversion.Text: toShortest :: Double -> Text

Files

− Data/Double/Conversion.hs
@@ -1,100 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface, MagicHash, Rank2Types,-    UnliftedFFITypes #-}---- |--- Module      : Data.Double.Conversion--- Copyright   : (c) 2011 MailRank, Inc.------ License     : BSD-style--- Maintainer  : bos@mailrank.com--- Stability   : experimental--- Portability : GHC------ Fast, efficient support for converting between double precision--- floating point values and text.--module Data.Double.Conversion-    (-      toExponential-    , toFixed-    , toPrecision-    , toShortest-    ) where--import Control.Monad (when)-import Control.Monad.ST (unsafeIOToST, runST)-import Data.Text.Internal (Text(Text))-import Foreign.C.Types (CDouble, CInt)-import GHC.Prim (MutableByteArray#)-import qualified Data.Text.Array as A---- | Compute a representation in exponential format with the requested--- number of digits after the decimal point. The last emitted digit is--- rounded.  If -1 digits are requested, then the shortest exponential--- representation is computed.-toExponential :: Int -> Double -> Text-toExponential ndigits = convert "toExponential" len $ \val mba ->-                        c_ToExponential val mba (fromIntegral ndigits)-  where len = c_ToExponentialLength-        {-# NOINLINE len #-}---- | Compute a decimal representation with a fixed number of digits--- after the decimal point. The last emitted digit is rounded.-toFixed :: Int -> Double -> Text-toFixed ndigits = convert "toFixed" len $ \val mba ->-                  c_ToFixed val mba (fromIntegral ndigits)-  where len = c_ToFixedLength-        {-# NOINLINE len #-}---- | Compute the shortest string of digits that correctly represent--- the input number.-toShortest :: Double -> Text-toShortest = convert "toShortest" len c_ToShortest-  where len = c_ToShortestLength-        {-# NOINLINE len #-}---- | Compute @precision@ leading digits of the given value either in--- exponential or decimal format. The last computed digit is rounded.-toPrecision :: Int -> Double -> Text-toPrecision ndigits = convert "toPrecision" len $ \val mba ->-                      c_ToPrecision val mba (fromIntegral ndigits)-  where len = c_ToPrecisionLength-        {-# NOINLINE len #-}--convert :: String -> CInt-        -> (forall s. CDouble -> MutableByteArray# s -> IO CInt)-        -> Double -> Text-convert func len act val = runST go-  where-    go = do-      buf <- A.new (fromIntegral len)-      size <- unsafeIOToST $ act (realToFrac val) (A.maBA buf)-      when (size == -1) .-        fail $ "Data.Double.Conversion." ++ func ++-               ": conversion failed (invalid precision requested)"-      frozen <- A.unsafeFreeze buf-      return $ Text frozen 0 (fromIntegral size)--foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortestLength"-    c_ToShortestLength :: CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortest"-    c_ToShortest :: CDouble -> MutableByteArray# s -> IO CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixedLength"-    c_ToFixedLength :: CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixed"-    c_ToFixed :: CDouble -> MutableByteArray# s -> CInt -> IO CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponentialLength"-    c_ToExponentialLength :: CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponential"-    c_ToExponential :: CDouble -> MutableByteArray# s -> CInt -> IO CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecisionLength"-    c_ToPrecisionLength :: CInt--foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecision"-    c_ToPrecision :: CDouble -> MutableByteArray# s -> CInt -> IO CInt
+ Data/Double/Conversion/ByteString.hs view
@@ -0,0 +1,76 @@+-- |+-- Module      : Data.Double.Conversion.ByteString+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@mailrank.com+-- Stability   : experimental+-- Portability : GHC+--+-- Fast, efficient support for converting between double precision+-- floating point values and text.+--+-- Although about 15 times faster than plain 'show', these functions+-- are /slower/ than their 'Text' counterparts, at roughly half the+-- speed.  (This seems to be due to the cost of allocating+-- 'ByteString' values via @malloc@.)++module Data.Double.Conversion.ByteString+    (+      toExponential+    , toFixed+    , toPrecision+    , toShortest+    ) where++import Control.Monad (when)+import Foreign.ForeignPtr (withForeignPtr)+import Data.Double.Conversion.FFI+import Data.Word (Word8)+import Data.ByteString.Internal (ByteString(..), mallocByteString)+import Foreign.C.Types (CDouble, CInt)+import Foreign.Ptr (Ptr)+import System.IO.Unsafe (unsafePerformIO)++-- | Compute a representation in exponential format with the requested+-- number of digits after the decimal point. The last emitted digit is+-- rounded.  If -1 digits are requested, then the shortest exponential+-- representation is computed.+toExponential :: Int -> Double -> ByteString+toExponential ndigits = convert "toExponential" len $ \val mba ->+                        c_ToExponential val mba (fromIntegral ndigits)+  where len = c_ToExponentialLength+        {-# NOINLINE len #-}++-- | Compute a decimal representation with a fixed number of digits+-- after the decimal point. The last emitted digit is rounded.+toFixed :: Int -> Double -> ByteString+toFixed ndigits = convert "toFixed" len $ \val mba ->+                  c_ToFixed val mba (fromIntegral ndigits)+  where len = c_ToFixedLength+        {-# NOINLINE len #-}++-- | Compute the shortest string of digits that correctly represent+-- the input number.+toShortest :: Double -> ByteString+toShortest = convert "toShortest" len c_ToShortest+  where len = c_ToShortestLength+        {-# NOINLINE len #-}++-- | Compute @precision@ leading digits of the given value either in+-- exponential or decimal format. The last computed digit is rounded.+toPrecision :: Int -> Double -> ByteString+toPrecision ndigits = convert "toPrecision" len $ \val mba ->+                      c_ToPrecision val mba (fromIntegral ndigits)+  where len = c_ToPrecisionLength+        {-# NOINLINE len #-}++convert :: String -> CInt -> (CDouble -> Ptr Word8 -> IO CInt)+        -> Double -> ByteString+convert func len act val = unsafePerformIO $ do+  fp <- mallocByteString (fromIntegral len)+  size <- withForeignPtr fp $ act (realToFrac val)+  when (size == -1) .+    fail $ "Data.Double.Conversion.ByteString." ++ func +++           ": conversion failed (invalid precision requested)"+  return $ PS fp 0 (fromIntegral size)
+ Data/Double/Conversion/FFI.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE ForeignFunctionInterface, MagicHash, UnliftedFFITypes #-}++-- |+-- Module      : Data.Double.Conversion.FFI+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@mailrank.com+-- Stability   : experimental+-- Portability : GHC+--+-- FFI interface support for converting between double precision+-- floating point values and text.++module Data.Double.Conversion.FFI+    (+      c_Text_ToExponential+    , c_Text_ToFixed+    , c_Text_ToPrecision+    , c_Text_ToShortest+    , c_ToExponentialLength+    , c_ToFixedLength+    , c_ToPrecisionLength+    , c_ToShortestLength+    , c_ToExponential+    , c_ToFixed+    , c_ToPrecision+    , c_ToShortest+    ) where++import Data.Word (Word8)+import Foreign.C.Types (CDouble, CInt)+import Foreign.Ptr (Ptr)+import GHC.Prim (MutableByteArray#)++foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortestLength"+    c_ToShortestLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_Text_ToShortest"+    c_Text_ToShortest :: CDouble -> MutableByteArray# s -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortest"+    c_ToShortest :: CDouble -> Ptr Word8 -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixedLength"+    c_ToFixedLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_Text_ToFixed"+    c_Text_ToFixed :: CDouble -> MutableByteArray# s -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixed"+    c_ToFixed :: CDouble -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponentialLength"+    c_ToExponentialLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_Text_ToExponential"+    c_Text_ToExponential :: CDouble -> MutableByteArray# s -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponential"+    c_ToExponential :: CDouble -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecisionLength"+    c_ToPrecisionLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_Text_ToPrecision"+    c_Text_ToPrecision :: CDouble -> MutableByteArray# s -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecision"+    c_ToPrecision :: CDouble -> Ptr Word8 -> CInt -> IO CInt
+ Data/Double/Conversion/Text.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE MagicHash, Rank2Types #-}++-- |+-- Module      : Data.Double.Conversion.Text+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@mailrank.com+-- Stability   : experimental+-- Portability : GHC+--+-- Fast, efficient support for converting between double precision+-- floating point values and text.+--+-- These functions are about 30 times faster than the default 'show'+-- implementation for the 'Double' type.++module Data.Double.Conversion.Text+    (+      toExponential+    , toFixed+    , toPrecision+    , toShortest+    ) where++import Control.Monad (when)+import Control.Monad.ST (unsafeIOToST, runST)+import Data.Double.Conversion.FFI+import Data.Text.Internal (Text(Text))+import Foreign.C.Types (CDouble, CInt)+import GHC.Prim (MutableByteArray#)+import qualified Data.Text.Array as A++-- | Compute a representation in exponential format with the requested+-- number of digits after the decimal point. The last emitted digit is+-- rounded.  If -1 digits are requested, then the shortest exponential+-- representation is computed.+toExponential :: Int -> Double -> Text+toExponential ndigits = convert "toExponential" len $ \val mba ->+                        c_Text_ToExponential val mba (fromIntegral ndigits)+  where len = c_ToExponentialLength+        {-# NOINLINE len #-}++-- | Compute a decimal representation with a fixed number of digits+-- after the decimal point. The last emitted digit is rounded.+toFixed :: Int -> Double -> Text+toFixed ndigits = convert "toFixed" len $ \val mba ->+                  c_Text_ToFixed val mba (fromIntegral ndigits)+  where len = c_ToFixedLength+        {-# NOINLINE len #-}++-- | Compute the shortest string of digits that correctly represent+-- the input number.+toShortest :: Double -> Text+toShortest = convert "toShortest" len c_Text_ToShortest+  where len = c_ToShortestLength+        {-# NOINLINE len #-}++-- | Compute @precision@ leading digits of the given value either in+-- exponential or decimal format. The last computed digit is rounded.+toPrecision :: Int -> Double -> Text+toPrecision ndigits = convert "toPrecision" len $ \val mba ->+                      c_Text_ToPrecision val mba (fromIntegral ndigits)+  where len = c_ToPrecisionLength+        {-# NOINLINE len #-}++convert :: String -> CInt+        -> (forall s. CDouble -> MutableByteArray# s -> IO CInt)+        -> Double -> Text+convert func len act val = runST go+  where+    go = do+      buf <- A.new (fromIntegral len)+      size <- unsafeIOToST $ act (realToFrac val) (A.maBA buf)+      when (size == -1) .+        fail $ "Data.Double.Conversion.Text." ++ func +++               ": conversion failed (invalid precision requested)"+      frozen <- A.unsafeFreeze buf+      return $ Text frozen 0 (fromIntegral size)
benchmarks/Benchmarks.hs view
@@ -1,20 +1,28 @@ {-# LANGUAGE ForeignFunctionInterface, OverloadedStrings #-}  import Criterion.Main-import Data.Double.Conversion+import qualified Data.Double.Conversion.ByteString as B+import qualified Data.Double.Conversion.Text as T import Foreign.C.Types (CInt, CDouble) import qualified Data.Text as T--showText :: Double -> T.Text-showText d = T.pack (show d)+import qualified Text.Show.ByteString as BS  main = defaultMain [          bgroup "haskell" [-           bench "show" $ whnf showText pi-         , bench "toShortest" $ whnf toShortest pi-         , bench "toExponential" $ whnf (toExponential 3) pi-         , bench "toPrecision" $ whnf (toExponential 8) pi-         , bench "toFixed" $ whnf (toFixed 8) pi+           bench "show" $ nf show (pi::Double)+         , bench "bytestring-show" $ whnf BS.show (pi::Double)+         , bgroup "text" [+             bench "toShortest" $ whnf T.toShortest pi+           , bench "toExponential" $ whnf (T.toExponential 3) pi+           , bench "toPrecision" $ whnf (T.toExponential 8) pi+           , bench "toFixed" $ whnf (T.toFixed 8) pi+           ]+         , bgroup "bytestring" [+             bench "toShortest" $ whnf B.toShortest pi+           , bench "toExponential" $ whnf (B.toExponential 3) pi+           , bench "toPrecision" $ whnf (B.toExponential 8) pi+           , bench "toFixed" $ whnf (B.toFixed 8) pi+           ]          ]        , bgroup "sprintf" [            bench "exact" $ whnf sprintf_exact pi
benchmarks/double-conversion-benchmarks.cabal view
@@ -10,6 +10,7 @@    build-depends:     base,+    bytestring-show,     criterion >= 0.5.0.10,     double-conversion,     text >= 0.11.0.8
cbits/hs-double-conversion.cc view
@@ -48,6 +48,13 @@   return pos; } +static int copy(uint16_t *buf, const char *cbuf, const int len)+{+  for (int i = 0; i < len; i++)+    buf[i] = cbuf[i];+  return len;+}+ static inline const DoubleToStringConverter& defaultConverter(void) {   const int flags = DoubleToStringConverter::UNIQUE_ZERO;@@ -61,53 +68,61 @@ }  extern "C"-int _hs_ToShortest(double value, uint16_t *buf)+int _hs_ToShortest(double value, char *buf) {-  char cbuf[kToShortestLength];-  StringBuilder builder(cbuf, kToShortestLength);-  bool ok = defaultConverter().ToShortest(value, &builder);+  StringBuilder builder(buf, kToShortestLength);+  return defaultConverter().ToShortest(value, &builder)+    ? builder.position() : -1;+} -  if (!ok)-    return -1;+extern "C"+int _hs_Text_ToShortest(double value, uint16_t *buf)+{+  char cbuf[kToShortestLength];+  return copy(buf, cbuf, _hs_ToShortest(value, cbuf));+} -  return copy(buf, builder, cbuf);+extern "C"+int _hs_ToFixed(double value, char *buf, const int ndigits)+{+  StringBuilder builder(buf, kToFixedLength);+  return defaultConverter().ToFixed(value, ndigits, &builder)+    ? builder.position() : -1; }  extern "C"-int _hs_ToFixed(double value, uint16_t *buf, const int ndigits)+int _hs_Text_ToFixed(double value, uint16_t *buf, const int ndigits) {   char cbuf[kToFixedLength];-  StringBuilder builder(cbuf, kToFixedLength);-  bool ok = defaultConverter().ToFixed(value, ndigits, &builder);+  return copy(buf, cbuf, _hs_ToFixed(value, cbuf, ndigits));+} -  if (!ok)-    return -1;-  -  return copy(buf, builder, cbuf);+extern "C"+int _hs_ToExponential(double value, char *buf, const int ndigits)+{+  StringBuilder builder(buf, kToExponentialLength);+  return defaultConverter().ToExponential(value, ndigits, &builder)+    ? builder.position() : -1; }  extern "C"-int _hs_ToExponential(double value, uint16_t *buf, const int ndigits)+int _hs_Text_ToExponential(double value, uint16_t *buf, const int ndigits) {   char cbuf[kToExponentialLength];-  StringBuilder builder(cbuf, kToExponentialLength);-  bool ok = defaultConverter().ToExponential(value, ndigits, &builder);+  return copy(buf, cbuf, _hs_ToExponential(value, cbuf, ndigits));+} -  if (!ok)-    return -1;-  -  return copy(buf, builder, cbuf);+extern "C"+int _hs_ToPrecision(double value, char *buf, const int precision)+{+  StringBuilder builder(buf, kToPrecisionLength);+  return defaultConverter().ToPrecision(value, precision, &builder)+    ? builder.position() : -1; }  extern "C"-int _hs_ToPrecision(double value, uint16_t *buf, const int precision)+int _hs_Text_ToPrecision(double value, uint16_t *buf, const int precision) {   char cbuf[kToPrecisionLength];-  StringBuilder builder(cbuf, kToPrecisionLength);-  bool ok = defaultConverter().ToPrecision(value, precision, &builder);--  if (!ok)-    return -1;-  -  return copy(buf, builder, cbuf);+  return copy(buf, cbuf, _hs_ToPrecision(value, cbuf, precision)); }
double-conversion.cabal view
@@ -1,5 +1,5 @@ name:           double-conversion-version:        0.1.0.0+version:        0.2.0.0 license:        BSD3 license-file:   LICENSE homepage:       https://github.com/mailrank/double-conversion@@ -13,9 +13,22 @@ cabal-version:  >= 1.8 build-type:     Simple description:-    A library that performs fast conversion between double precision-    floating point and text, implemented as bindings to the C++-    double-conversion library written by Florian Loitsch at Google.+    A library that performs fast, accurate conversion between double+    precision floating point and text.+    .+    This library is implemented as bindings to the C+++    @double-conversion@ library written by Florian Loitsch at Google:+    <http://code.google.com/p/double-conversion/>.+    .+    The 'Text' versions of these functions are about 30 times faster+    than the default 'show' implementation for the 'Double' type.+    .+    The 'ByteString' versions are /slower/ than the 'Text' versions;+    roughly half the speed.  (This seems to be due to the cost of+    allocating 'ByteString' values via @malloc@.)+    .+    As a final note, be aware that the @bytestring-show@ package is+    about 50% slower than simply using 'show'.  extra-source-files:     README.markdown@@ -59,10 +72,15 @@     include    exposed-modules:-    Data.Double.Conversion+    Data.Double.Conversion.ByteString+    Data.Double.Conversion.Text +  other-modules:+    Data.Double.Conversion.FFI+   build-depends:     base == 4.*,+    bytestring,     ghc-prim,     text >= 0.11.0.8 
include/hs-double-conversion.h view
@@ -9,13 +9,17 @@ #include <stddef.h>  int _hs_ToShortestLength(void);-int _hs_ToShortest(double value, uint16_t *buf);+int _hs_Text_ToShortest(double value, uint16_t *buf);+int _hs_ToShortest(double value, char *buf); int _hs_ToFixedLength(void);-int _hs_ToFixed(double value, uint16_t *buf, int ndigits);+int _hs_Text_ToFixed(double value, uint16_t *buf, int ndigits);+int _hs_ToFixed(double value, char *buf, int ndigits); int _hs_ToExponentialLength(void);-int _hs_ToExponential(double value, uint16_t *buf, int ndigits);+int _hs_Text_ToExponential(double value, uint16_t *buf, int ndigits);+int _hs_ToExponential(double value, char *buf, int ndigits); int _hs_ToPrecisionLength(void);-int _hs_ToPrecision(double value, uint16_t *buf, int ndigits);+int _hs_Text_ToPrecision(double value, uint16_t *buf, int ndigits);+int _hs_ToPrecision(double value, char *buf, int ndigits);  #ifdef __cplusplus }