double-conversion 2.0.2.0 → 2.0.5.0
raw patch · 35 files changed
Files
- Data/Double/Conversion/ByteString.hs +13/−33
- Data/Double/Conversion/Convertable.hs +296/−0
- Data/Double/Conversion/FFI.hs +0/−74
- Data/Double/Conversion/Internal/ByteString.hs +44/−0
- Data/Double/Conversion/Internal/ByteStringBuilder.hs +37/−0
- Data/Double/Conversion/Internal/FFI.hs +125/−0
- Data/Double/Conversion/Internal/Text.hs +58/−0
- Data/Double/Conversion/Internal/TextBuilder.hs +54/−0
- Data/Double/Conversion/Text.hs +13/−41
- README.markdown +4/−10
- benchmarks/Benchmarks.hs +104/−12
- benchmarks/double-conversion-benchmarks.cabal +1/−0
- cbits/hs-double-conversion-embed.cc +199/−0
- cbits/hs-double-conversion.cc +72/−1
- double-conversion.cabal +64/−38
- double-conversion/CMakeLists.txt +93/−75
- double-conversion/Changelog +30/−0
- double-conversion/SConstruct +2/−2
- double-conversion/test/cctest/cctest.h +10/−7
- double-conversion/test/cctest/gay-fixed.cc too large to diff
- double-conversion/test/cctest/gay-precision.cc too large to diff
- double-conversion/test/cctest/gay-shortest-single.cc +1/−1
- double-conversion/test/cctest/gay-shortest.cc too large to diff
- double-conversion/test/cctest/test-bignum-dtoa.cc +3/−3
- double-conversion/test/cctest/test-bignum.cc +3/−2
- double-conversion/test/cctest/test-conversions.cc +60/−5
- double-conversion/test/cctest/test-diy-fp.cc +2/−2
- double-conversion/test/cctest/test-dtoa.cc +2/−2
- double-conversion/test/cctest/test-fast-dtoa.cc +4/−4
- double-conversion/test/cctest/test-fixed-dtoa.cc +7/−3
- double-conversion/test/cctest/test-ieee.cc +3/−4
- double-conversion/test/cctest/test-strtod.cc +5/−5
- include/hs-double-conversion.h +8/−0
- tests/Properties.hs +3/−4
- tests/Regressions.hs +2/−2
Data/Double/Conversion/ByteString.hs view
@@ -7,6 +7,13 @@ -- Stability : experimental -- Portability : GHC --+-- This module left now only for compatibility and should not be used+-- in new projects. +-- Please, use Convertable type class from Data.Double.Conversion.Convertable+-- +-- It is espesially recommended to convert a large amount of numbers via bytestring builder+-- using methods of Convertable type class. It is about 10-15x faster. +-- -- Fast, efficient support for converting between double precision -- floating point values and text. --@@ -23,54 +30,27 @@ , 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)+import qualified Data.Double.Conversion.Convertable+import Data.ByteString.Internal -- | 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 #-}+toExponential = Data.Double.Conversion.Convertable.toExponential -- | 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 #-}+toFixed = Data.Double.Conversion.Convertable.toFixed -- | 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 #-}+toShortest = Data.Double.Conversion.Convertable.toShortest -- | 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)+toPrecision = Data.Double.Conversion.Convertable.toPrecision
+ Data/Double/Conversion/Convertable.hs view
@@ -0,0 +1,296 @@+{-# LANGUAGE DefaultSignatures, InstanceSigs, MagicHash, MultiParamTypeClasses,+ TypeFamilies, TypeOperators #-}++-- |+-- Module : Data.Double.Conversion.Convertable+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC++module Data.Double.Conversion.Convertable+ ( Convertable(..)+ ) where+import Data.ByteString.Builder.Prim (primBounded)+import Data.Text (Text)++import Data.Double.Conversion.Internal.FFI+import Data.String (IsString)++import qualified Data.ByteString.Builder as BB (Builder)+import qualified Data.ByteString.Internal as B (ByteString(..))+import qualified Data.Double.Conversion.Internal.ByteString as CB (convert)+import qualified Data.Double.Conversion.Internal.ByteStringBuilder as CBB (convert)+import qualified Data.Double.Conversion.Internal.Text as CT (convert)+import qualified Data.Double.Conversion.Internal.TextBuilder as CTB (convert)+import qualified Data.Text.Internal.Builder as T (Builder)++-- | Type class for floating data types, that can be converted, using double-conversion library+--+-- Default instanced convert input to Double and then make Bytestring Builder from it.+--+-- list of functions :+--+-- toExponential:+-- 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.+--+-- toPrecision:+-- Compute @precision@ leading digits of the given value either in+-- exponential or decimal format. The last computed digit is rounded.+--+-- toFixed:+-- Compute a decimal representation with a fixed number of digits+-- after the decimal point. The last emitted digit is rounded.+--+-- toShortest:+-- Compute the shortest string of digits that correctly represent+-- the input number.+--+-- Conversion to text via Builder (both in the in case of bytestring and text) in case of single number+-- is a bit slower, than to text or bytestring directly.+-- But conversion a large amount of numbers to text via Builder (for example using foldr) is much faster than direct conversion to Text (up to 10-15x).+--+-- The same works for bytestrings: conversion, for example, a list of 20000 doubles to bytestring builder +-- and then to bytestring is about 13 times faster than direct conversion of this list to bytestring. +--+-- Conversion to text via text builder is a little bit slower, than conversion to bytestring via bytestring builder. +++class (RealFloat a, IsString b) => Convertable a b where+ toExponential :: Int -> a -> b+ default toExponential :: (b ~ BB.Builder) => Int -> a -> b+ toExponential ndigits num = primBounded (CBB.convert "toExponential" len $ \val mba ->+ c_ToExponential val mba (fromIntegral ndigits)) (realToFrac num :: Double)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> a -> b+ default toPrecision :: (b ~ BB.Builder) => Int -> a -> b+ toPrecision ndigits num = primBounded (CBB.convert "toPrecision" len $ \val mba ->+ c_ToPrecision val mba (fromIntegral ndigits)) (realToFrac num :: Double)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}++ toFixed :: Int -> a -> b+ default toFixed :: (b ~ BB.Builder) => Int -> a -> b+ toFixed ndigits num = primBounded (CBB.convert "toFixed" len $ \val mba ->+ c_ToFixed val mba (fromIntegral ndigits)) (realToFrac num :: Double)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: a -> b+ default toShortest :: (b ~ BB.Builder) => a -> b+ toShortest num = primBounded (CBB.convert "toShortest" len c_ToShortest) (realToFrac num :: Double)+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++-- Instances++instance Convertable Double BB.Builder where+ toExponential :: Int -> Double -> BB.Builder+ toExponential ndigits = primBounded $ CBB.convert "toExponential" len $ \val mba ->+ c_ToExponential val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Double -> BB.Builder+ toPrecision ndigits = primBounded (CBB.convert "toPrecision" len $ \val mba ->+ c_ToPrecision val mba (fromIntegral ndigits))+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}++ toShortest :: Double -> BB.Builder+ toShortest = primBounded $ CBB.convert "toShortest" len c_ToShortest+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Double -> BB.Builder+ toFixed ndigits = primBounded $ CBB.convert "toFixed" len $ \val mba ->+ c_ToFixed val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}+++instance Convertable Float BB.Builder where+ toExponential :: Int -> Float -> BB.Builder+ toExponential ndigits = primBounded $ CBB.convert "toExponential" len $ \val mba ->+ c_ToExponentialFloat val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Float -> BB.Builder+ toPrecision ndigits = primBounded (CBB.convert "toPrecision" len $ \val mba ->+ c_ToPrecisionFloat val mba (fromIntegral ndigits))+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}++ toShortest :: Float -> BB.Builder+ toShortest = primBounded $ CBB.convert "toShortest" len c_ToShortestFloat+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Float -> BB.Builder+ toFixed ndigits = primBounded $ CBB.convert "toFixed" len $ \val mba ->+ c_ToFixedFloat val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++-- Fast conversion to bytestring.+-- 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@.)++instance Convertable Double B.ByteString where+ toExponential :: Int -> Double -> B.ByteString+ toExponential ndigits = CB.convert "toExponential" len $ \val mba ->+ c_ToExponential val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Double -> B.ByteString+ toFixed ndigits = CB.convert "toFixed" len $ \val mba ->+ c_ToFixed val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: Double -> B.ByteString+ toShortest = CB.convert "toShortest" len c_ToShortest+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Double -> B.ByteString+ toPrecision ndigits = CB.convert "toPrecision" len $ \val mba ->+ c_ToPrecision val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}+++instance Convertable Float B.ByteString where+ toExponential :: Int -> Float -> B.ByteString+ toExponential ndigits = CB.convert "toExponential" len $ \val mba ->+ c_ToExponentialFloat val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Float -> B.ByteString+ toFixed ndigits = CB.convert "toFixed" len $ \val mba ->+ c_ToFixedFloat val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: Float -> B.ByteString+ toShortest = CB.convert "toShortest" len c_ToShortestFloat+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Float -> B.ByteString+ toPrecision ndigits = CB.convert "toPrecision" len $ \val mba ->+ c_ToPrecisionFloat val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}+++instance Convertable Double Text where+ toExponential :: Int -> Double -> Text+ toExponential ndigits = CT.convert "toExponential" len $ \val mba ->+ c_Text_ToExponential val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Double -> Text+ toFixed ndigits = CT.convert "toFixed" len $ \val mba ->+ c_Text_ToFixed val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: Double -> Text+ toShortest = CT.convert "toShortest" len c_Text_ToShortest+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Double -> Text+ toPrecision ndigits = CT.convert "toPrecision" len $ \val mba ->+ c_Text_ToPrecision val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}+++instance Convertable Float Text where+ toExponential :: Int -> Float -> Text+ toExponential ndigits = CT.convert "toExponential" len $ \val mba ->+ c_Text_ToExponentialFloat val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Float -> Text+ toFixed ndigits = CT.convert "toFixed" len $ \val mba ->+ c_Text_ToFixedFloat val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: Float -> Text+ toShortest = CT.convert "toShortest" len c_Text_ToShortestFloat+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Float -> Text+ toPrecision ndigits = CT.convert "toPrecision" len $ \val mba ->+ c_Text_ToPrecisionFloat val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}+++instance Convertable Double T.Builder where+ toExponential :: Int -> Double -> T.Builder+ toExponential ndigits = CTB.convert "toExponential" len $ \val mba ->+ c_Text_ToExponential val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Double -> T.Builder+ toFixed ndigits = CTB.convert "toFixed" len $ \val mba ->+ c_Text_ToFixed val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: Double -> T.Builder+ toShortest = CTB.convert "toShortest" len c_Text_ToShortest+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Double -> T.Builder+ toPrecision ndigits = CTB.convert "toPrecision" len $ \val mba ->+ c_Text_ToPrecision val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}+++instance Convertable Float T.Builder where+ toExponential :: Int -> Float -> T.Builder+ toExponential ndigits = CTB.convert "toExponential" len $ \val mba ->+ c_Text_ToExponentialFloat val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++ toFixed :: Int -> Float -> T.Builder+ toFixed ndigits = CTB.convert "toFixed" len $ \val mba ->+ c_Text_ToFixedFloat val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++ toShortest :: Float -> T.Builder+ toShortest = CTB.convert "toShortest" len c_Text_ToShortestFloat+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++ toPrecision :: Int -> Float -> T.Builder+ toPrecision ndigits = CTB.convert "toPrecision" len $ \val mba ->+ c_Text_ToPrecisionFloat val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}
− Data/Double/Conversion/FFI.hs
@@ -1,74 +0,0 @@-{-# LANGUAGE CPP, ForeignFunctionInterface, MagicHash, UnliftedFFITypes #-}---- |--- Module : Data.Double.Conversion.FFI--- Copyright : (c) 2011 MailRank, Inc.------ License : BSD-style--- Maintainer : bos@serpentine.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)-#if __GLASGOW_HASKELL__ >= 703-import Foreign.C.Types (CDouble(CDouble), CInt(CInt))-#else-import Foreign.C.Types (CDouble, CInt)-#endif-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/Internal/ByteString.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE TypeFamilies, TypeOperators #-}++-- |+-- Module : Data.Double.Conversion.ByteString+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@serpentine.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.Internal.ByteString+ ( convert+ ) where++import Control.Monad (when)+import Data.ByteString.Internal (ByteString(..), mallocByteString)+import Data.Double.Conversion.Internal.FFI (ForeignFloating)+import Data.Word (Word8)+import Foreign.C.Types (CDouble, CFloat, CInt)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (Ptr)+import System.IO.Unsafe (unsafePerformIO)++convert :: (RealFloat a, RealFloat b , b ~ ForeignFloating a) => String -> CInt -> (b -> Ptr Word8 -> IO CInt)+ -> a -> ByteString+{-# SPECIALIZE convert :: String -> CInt -> (CDouble -> Ptr Word8 -> IO CInt) -> Double -> ByteString #-}+{-# SPECIALIZE convert :: String -> CInt -> (CFloat -> Ptr Word8 -> IO CInt) -> Float -> ByteString #-}+{-# INLINABLE convert #-}+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/Internal/ByteStringBuilder.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE TypeFamilies, TypeOperators #-}++-- |+-- Module : Data.Double.Conversion.ByteStringBuilder+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC+--+-- Fast, efficient support for converting between double precision+-- floating point values and bytestring builder.++module Data.Double.Conversion.Internal.ByteStringBuilder+ (convert+ ) where++import Control.Monad (when)++import Data.ByteString.Builder.Prim.Internal (BoundedPrim, boudedPrim)++import Data.Double.Conversion.Internal.FFI (ForeignFloating)+import Data.Word (Word8)+import Foreign.C.Types (CDouble, CFloat, CInt)+import Foreign.Ptr (Ptr, plusPtr)++convert :: (RealFloat a, RealFloat b , b ~ ForeignFloating a) => String -> CInt -> (b -> Ptr Word8 -> IO CInt) -> BoundedPrim a+{-# SPECIALIZE convert :: String -> CInt -> (CDouble -> Ptr Word8 -> IO CInt) -> BoundedPrim Double #-}+{-# SPECIALIZE convert :: String -> CInt -> (CFloat -> Ptr Word8 -> IO CInt) -> BoundedPrim Float #-}+{-# INLINABLE convert #-}+convert func len act = boudedPrim (fromIntegral len) $ \val ptr -> do+ size <- act (realToFrac val) ptr+ when (size == -1) .+ fail $ "Data.Double.Conversion.ByteString." ++ func +++ ": conversion failed (invalid precision requested)"+ return (ptr `plusPtr` (fromIntegral size))
+ Data/Double/Conversion/Internal/FFI.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE CPP, ForeignFunctionInterface, MagicHash, TypeFamilies,+ UnliftedFFITypes #-}++-- |+-- Module : Data.Double.Conversion.FFI+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC+--+-- FFI interface support for converting between+-- floating point values and text.++module Data.Double.Conversion.Internal.FFI+ (+ ForeignFloating+ , c_Text_ToExponential+ , c_Text_ToExponentialFloat+ , c_Text_ToFixed+ , c_Text_ToFixedFloat+ , c_Text_ToPrecision+ , c_Text_ToPrecisionFloat+ , c_Text_ToShortest+ , c_Text_ToShortestFloat+ , c_ToExponentialLength+ , c_ToFixedLength+ , c_ToPrecisionLength+ , c_ToShortestLength+ , c_ToExponential+ , c_ToExponentialFloat+ , c_ToFixed+ , c_ToFixedFloat+ , c_ToPrecision+ , c_ToPrecisionFloat+ , c_ToShortest+ , c_ToShortestFloat+ ) where++import Data.Word (Word8)+#if __GLASGOW_HASKELL__ >= 703+import Foreign.C.Types (CDouble(CDouble), CFloat(CFloat), CInt(CInt))+#else+import Foreign.C.Types (CDouble, CFloat, CInt)+#endif+import Foreign.Ptr (Ptr)+import GHC.Prim (MutableByteArray#)++type family ForeignFloating h :: *++type instance ForeignFloating Double = CDouble+type instance ForeignFloating Float = CFloat++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 -> Ptr Word8 -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortestFloat"+ c_ToShortestFloat :: CFloat -> 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_ToFixed"+ c_ToFixed :: CDouble -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixedFloat"+ c_ToFixedFloat :: CFloat -> 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_ToExponential"+ c_ToExponential :: CDouble -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponentialFloat"+ c_ToExponentialFloat :: CFloat -> 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_ToPrecision"+ c_ToPrecision :: CDouble -> Ptr Word8 -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecisionFloat"+ c_ToPrecisionFloat :: CFloat -> Ptr Word8 -> CInt -> IO CInt++#if MIN_VERSION_text(2,0,0)+foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortest"+ c_Text_ToShortest :: CDouble -> MutableByteArray# s -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortestFloat"+ c_Text_ToShortestFloat :: CFloat -> MutableByteArray# s -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixed"+ c_Text_ToFixed :: CDouble -> MutableByteArray# s -> CInt -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixedFloat"+ c_Text_ToFixedFloat :: CFloat -> MutableByteArray# s-> CInt -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponential"+ c_Text_ToExponential :: CDouble -> MutableByteArray# s -> CInt -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponentialFloat"+ c_Text_ToExponentialFloat :: CFloat -> MutableByteArray# s -> CInt -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecision"+ c_Text_ToPrecision :: CDouble -> MutableByteArray# s -> CInt -> IO CInt+foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecisionFloat"+ c_Text_ToPrecisionFloat :: CFloat -> MutableByteArray# s -> CInt -> IO CInt+#else+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_Text_ToShortestFloat"+ c_Text_ToShortestFloat :: CFloat -> MutableByteArray# s -> IO 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_Text_ToFixedFloat"+ c_Text_ToFixedFloat :: CFloat -> MutableByteArray# s -> CInt -> IO 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_Text_ToExponentialFloat"+ c_Text_ToExponentialFloat :: CFloat -> MutableByteArray# s -> CInt -> IO 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_Text_ToPrecisionFloat"+ c_Text_ToPrecisionFloat :: CFloat -> MutableByteArray# s -> CInt -> IO CInt+#endif
+ Data/Double/Conversion/Internal/Text.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies, BangPatterns, TypeOperators #-}++-- |+-- Module : Data.Double.Conversion.Text+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@serpentine.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.Internal.Text+ (+ convert+ ) where++import Control.Monad (when)+#if MIN_VERSION_base(4,4,0)+import Control.Monad.ST.Unsafe (unsafeIOToST)+#else+import Control.Monad.ST (unsafeIOToST)+#endif+import Control.Monad.ST (ST, runST)+import Data.Double.Conversion.Internal.FFI (ForeignFloating)+import qualified Data.Text.Array as A+import Data.Text.Internal (Text(Text))+import Foreign.C.Types (CDouble, CFloat, CInt)+import GHC.Prim (MutableByteArray#)+++convert :: (RealFloat a, RealFloat b, b ~ ForeignFloating a) => String -> CInt+ -> (forall s. b -> MutableByteArray# s -> IO CInt)+ -> a -> Text+{-# SPECIALIZE convert :: String -> CInt -> (forall s. CDouble -> MutableByteArray# s -> IO CInt) -> Double -> Text #-}+{-# SPECIALIZE convert :: String -> CInt -> (forall s. CFloat -> MutableByteArray# s -> IO CInt) -> Float -> Text #-}+{-# INLINABLE convert #-}+convert func len act val = runST go+ where+ go :: (forall s. ST s Text)+ go = do+ buf <- A.new (fromIntegral len)+#if MIN_VERSION_text(2,0,0)+ let !(A.MutableByteArray ma) = buf+#else+ let ma = A.maBA buf+#endif+ size <- unsafeIOToST $ act (realToFrac val) ma+ when (size == -1) .+ error $ "Data.Double.Conversion.Text." ++ func +++ ": conversion failed (invalid precision requested)"+ frozen <- A.unsafeFreeze buf+ return $ Text frozen 0 (fromIntegral size)
+ Data/Double/Conversion/Internal/TextBuilder.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies, TypeOperators #-}+-- |+-- Module : Data.Double.Conversion.TextBuilder+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC+--+-- Fast, efficient support for converting between double precision+-- floating point values and text.+--++module Data.Double.Conversion.Internal.TextBuilder+ (+ convert+ ) where++import Control.Monad (when)+#if MIN_VERSION_base(4,4,0)+import Control.Monad.ST.Unsafe (unsafeIOToST)+#else+import Control.Monad.ST (unsafeIOToST)+#endif+import Data.Double.Conversion.Internal.FFI (ForeignFloating)+import qualified Data.Text.Array as A+import Data.Text.Internal.Builder (Builder, writeN)+import Foreign.C.Types (CDouble, CFloat, CInt)+import GHC.Prim (MutableByteArray#)+import Control.Monad.ST (runST)++convert :: (RealFloat a, RealFloat b, b ~ ForeignFloating a) => String -> CInt+ -> (forall s. b -> MutableByteArray# s -> IO CInt)+ -> a -> Builder+{-# SPECIALIZE convert :: String -> CInt -> (forall s. CDouble -> MutableByteArray# s -> IO CInt) -> Double -> Builder #-}+{-# SPECIALIZE convert :: String -> CInt -> (forall s. CFloat -> MutableByteArray# s -> IO CInt) -> Float -> Builder #-}+{-# INLINABLE convert #-}+convert func len act val = runST $ do +#if MIN_VERSION_text(2,0,0)+ mTempArr@(A.MutableByteArray tempMArr) <- A.new (fromIntegral len)+#else+ mTempArr@(A.MArray tempMArr) <- A.new (fromIntegral len)+#endif+ size <- unsafeIOToST $ act (realToFrac val) tempMArr+ tempArr <- A.unsafeFreeze mTempArr+ when (size == -1) .+ error $ "Data.Double.Conversion.Text." ++ func +++ ": conversion failed."+#if MIN_VERSION_text(2,0,0)+ return $ writeN (fromIntegral size) $ \mArr _ -> A.copyI (fromIntegral size) mArr 0 tempArr 0+#else+ return $ writeN (fromIntegral size) $ \mArr _ -> A.copyI mArr 0 tempArr 0 (fromIntegral size)+#endif
Data/Double/Conversion/Text.hs view
@@ -9,6 +9,13 @@ -- Stability : experimental -- Portability : GHC --+-- This module left now only for compatibility and should not be used+-- in new projects. +-- Please, use Convertable type class from Data.Double.Conversion.Convertable+--+-- It is espesially recommended to convert a large amount of numbers via text builder+-- using methods of Convertable type class. It is about 10-15x faster.+-- -- Fast, efficient support for converting between double precision -- floating point values and text. --@@ -23,62 +30,27 @@ , toShortest ) where -import Control.Monad (when)-#if MIN_VERSION_base(4,4,0)-import Control.Monad.ST.Unsafe (unsafeIOToST)-#else-import Control.Monad.ST (unsafeIOToST)-#endif-import Control.Monad.ST (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+import qualified Data.Double.Conversion.Convertable+import Data.Text.Internal (Text) -- | 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 #-}+toExponential = Data.Double.Conversion.Convertable.toExponential -- | 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 #-}+toFixed = Data.Double.Conversion.Convertable.toFixed -- | 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 #-}+toShortest = Data.Double.Conversion.Convertable.toShortest -- | 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)+toPrecision = Data.Double.Conversion.Convertable.toPrecision
README.markdown view
@@ -3,7 +3,7 @@ double-conversion is a fast Haskell library for converting between double precision floating point numbers and text strings. It is implemented as a binding to the V8-derived C++ [double-conversion-library](https://github.com/floitsch/double-conversion).+library](https://github.com/google/double-conversion). # Join in! @@ -11,17 +11,11 @@ and other improvements. Please report bugs via the-[github issue tracker](https://github.com/bos/double-conversion/issues).--Master [git repository](https://github.com/bos/double-conversion):--* `git clone git://github.com/bos/double-conversion.git`--There's also a [Mercurial mirror](https://bitbucket.org/bos/double-conversion):+[github issue tracker](https://github.com/haskell/double-conversion/issues). -* `hg clone https://bitbucket.org/bos/double-conversion`+Master [git repository](https://github.com/haskell/double-conversion): -(You can create and contribute changes using either git or Mercurial.)+* `git clone git://github.com/haskell/double-conversion` Authors -------
benchmarks/Benchmarks.hs view
@@ -1,28 +1,120 @@ {-# LANGUAGE ForeignFunctionInterface, OverloadedStrings #-} import Criterion.Main-import qualified Data.Double.Conversion.ByteString as B-import qualified Data.Double.Conversion.Text as T-import Foreign.C.Types (CInt(CInt), CDouble(CDouble))+import qualified Data.ByteString as BSS+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Builder.Extra as BBE+import qualified Data.ByteString.Lazy as BSL+import qualified Data.Double.Conversion.Convertable as BL+import Data.List (foldr)+import Data.Monoid ((<>)) import qualified Data.Text as T+import qualified Data.Text.Internal.Builder as BT+import qualified Data.Text.Lazy as TL+import Foreign.C.Types (CDouble(CDouble), CInt(CInt)) import qualified Text.Show.ByteString as BS +testList = [2.08345919 .. 20002.08345919] :: [Double]+testFloatList = [2.08345919 .. 20002.08345919] :: [Float]++testListBSBuilder :: (Double -> BB.Builder) -> [Double] -> BSS.ByteString+testListBSBuilder func list = BSL.toStrict $ BBE.toLazyByteStringWith (BBE.safeStrategy 128 128) BSL.empty $ foldr (\x y -> (func x <> ", ") <> y) mempty list++testListBSBuilderFloat :: (Float -> BB.Builder) -> [Float] -> BSS.ByteString+testListBSBuilderFloat func list = BSL.toStrict $ BBE.toLazyByteStringWith (BBE.safeStrategy 128 128) BSL.empty $ foldr (\x y -> (func x <> ", ") <> y) mempty list++testListByteString :: (Double -> BSS.ByteString) -> [Double] -> BSS.ByteString+testListByteString func = foldr (\x y -> (func x <> ", ") <> y) mempty++testListByteStringFloat :: (Float -> BSS.ByteString) -> [Float] -> BSS.ByteString+testListByteStringFloat func = foldr (\x y -> (func x <> ", ") <> y) mempty++testListText :: (Double -> T.Text) -> [Double] -> T.Text+testListText func = foldr (\x y -> (func x <> ", ") <> y) mempty++testListTextFloat :: (Float -> T.Text) -> [Float] -> T.Text+testListTextFloat func = foldr (\x y -> (func x <> ", ") <> y) mempty++testListTextBuilder :: (Double -> BT.Builder) -> [Double] -> T.Text+testListTextBuilder func list = TL.toStrict $ BT.toLazyText $ foldr (\x y -> (func x <> ", ") <> y) mempty list++testListTextBuilderFloat :: (Float -> BT.Builder) -> [Float] -> T.Text+testListTextBuilderFloat func list = TL.toStrict $ BT.toLazyText $ foldr (\x y -> (func x <> ", ") <> y) mempty list++testFuncBuilderDefault :: [Double] -> BSS.ByteString+testFuncBuilderDefault = \list -> BSL.toStrict $ BB.toLazyByteString $ foldr (\x y -> (BB.doubleDec x <> ", ") <> y) mempty list++testFuncBuilderDefaultFloat :: [Float] -> BSS.ByteString+testFuncBuilderDefaultFloat = \list -> BSL.toStrict $ BB.toLazyByteString $ foldr (\x y -> (BB.floatDec x <> ", ") <> y) mempty list++ main = defaultMain [- bgroup "haskell" [+ bgroup "haskell-single" [ 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+ bench "toShortest" $ whnf (BL.toShortest :: Double -> T.Text) pi+ , bench "toExponential" $ whnf ((BL.toExponential 3) :: Double -> T.Text) pi+ , bench "toPrecision" $ whnf ((BL.toExponential 8) :: Double -> T.Text) pi+ , bench "toFixed" $ whnf ((BL.toFixed 8) :: Double -> T.Text) 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+ bench "toShortest" $ whnf (BL.toShortest :: Double -> BSS.ByteString) pi+ , bench "toExponential" $ whnf ((BL.toExponential 3) :: Double -> BSS.ByteString) pi+ , bench "toPrecision" $ whnf ((BL.toExponential 8) :: Double -> BSS.ByteString) pi+ , bench "toFixed" $ whnf ((BL.toFixed 8) :: Double -> BSS.ByteString) pi ]+ , bgroup "bytestringBuilder" [+ bench "toShortest" $ nf (BB.toLazyByteString . BL.toShortest) (pi::Double)+ , bench "toPrecision" $ nf (BB.toLazyByteString . (BL.toExponential 8)) (pi::Double)+ , bench "toPrecision" $ nf (BB.toLazyByteString . (BL.toPrecision 8)) (pi::Double)+ , bench "toFixed" $ nf (BB.toLazyByteString . (BL.toFixed 8)) (pi::Double)+ ]+ ]+ , bgroup "Haskell-list" [+ bgroup "bytestring" [+ bench "toShortest" $ nf (testListByteString BL.toShortest) testList+ , bench "toExponential" $ nf (testListByteString $ BL.toExponential 8) testList+ , bench "toPrecision" $ nf (testListByteString $ BL.toPrecision 8) testList+ , bench "toFixed" $ nf (testListByteString $ BL.toFixed 8) testList]+ , bgroup "bytestring-float" [+ bench "toShortest" $ nf (testListByteStringFloat BL.toShortest) testFloatList+ , bench "toExponential" $ nf (testListByteStringFloat $ BL.toExponential 8) testFloatList+ , bench "toPrecision" $ nf (testListByteStringFloat $ BL.toPrecision 8) testFloatList+ , bench "toFixed" $ nf (testListByteStringFloat $ BL.toFixed 8) testFloatList]+ , bgroup "bytestring-builder" [+ bench "toShortest" $ nf (testListBSBuilder BL.toShortest) testList+ , bench "toExponential" $ nf (testListBSBuilder $ BL.toExponential 8) testList+ , bench "toPrecision" $ nf (testListBSBuilder $ BL.toPrecision 8) testList+ , bench "toFixed" $ nf (testListBSBuilder $ BL.toFixed 8) testList ]+ , bgroup "bytestring-builder-float" [+ bench "toShortest" $ nf (testListBSBuilderFloat BL.toShortest) testFloatList+ , bench "toExponential" $ nf (testListBSBuilderFloat $ BL.toExponential 8) testFloatList+ , bench "toPrecision" $ nf (testListBSBuilderFloat $ BL.toPrecision 8) testFloatList+ , bench "toFixed" $ nf (testListBSBuilderFloat $ BL.toFixed 8) testFloatList ]+ , bgroup "text" [+ bench "toShortest" $ nf (testListText BL.toShortest) testList+ , bench "toExponential" $ nf (testListText $ BL.toExponential 8) testList+ , bench "toPrecision" $ nf (testListText $ BL.toPrecision 8) testList+ , bench "toFixed" $ nf (testListText $ BL.toFixed 8) testList ]+ , bgroup "text-float" [+ bench "toShortest" $ nf (testListTextFloat BL.toShortest) testFloatList+ , bench "toExponential" $ nf (testListTextFloat $ BL.toExponential 8) testFloatList+ , bench "toPrecision" $ nf (testListTextFloat $ BL.toPrecision 8) testFloatList+ , bench "toFixed" $ nf (testListTextFloat $ BL.toFixed 8) testFloatList ]+ , bgroup "text-builder" [+ bench "toShortest" $ nf (testListTextBuilder BL.toShortest) testList+ , bench "toExponential" $ nf (testListTextBuilder $ BL.toExponential 8) testList+ , bench "toPrecision" $ nf (testListTextBuilder$ BL.toPrecision 8) testList+ , bench "toFixed" $ nf (testListTextBuilder $ BL.toFixed 8) testList ]+ , bgroup "text-builder-float" [+ bench "toShortest" $ nf (testListTextBuilderFloat BL.toShortest) testFloatList+ , bench "toExponential" $ nf (testListTextBuilderFloat $ BL.toExponential 8) testFloatList+ , bench "toPrecision" $ nf (testListTextBuilderFloat $ BL.toPrecision 8) testFloatList+ , bench "toFixed" $ nf (testListTextBuilderFloat $ BL.toFixed 8) testFloatList ]+ , bgroup "bytestring-builder-default" [+ bench "Double" $ nf (testFuncBuilderDefault) testList+ , bench "Float" $ nf (testFuncBuilderDefaultFloat) testFloatList ] ] , bgroup "sprintf" [ bench "exact" $ whnf sprintf_exact pi
benchmarks/double-conversion-benchmarks.cabal view
@@ -10,6 +10,7 @@ build-depends: base,+ bytestring, bytestring-show, criterion >= 0.5.0.10, double-conversion,
+ cbits/hs-double-conversion-embed.cc view
@@ -0,0 +1,199 @@+#include "double-conversion.h"+#include "hs-double-conversion.h"+#include <stdio.h>++using namespace double_conversion;++static const int kToShortestLength = 26;++extern "C"+int _hs_ToShortestLength(void)+{+ return kToShortestLength;+}++static const int kToFixedLength =+ 1 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint ++ 1 + DoubleToStringConverter::kMaxFixedDigitsAfterPoint;++extern "C"+int _hs_ToFixedLength(void)+{+ return kToFixedLength;+}++static const int kToExponentialLength =+ DoubleToStringConverter::kMaxExponentialDigits + 8;++extern "C"+int _hs_ToExponentialLength(void)+{+ return kToExponentialLength;+}++static const int kToPrecisionLength =+ DoubleToStringConverter::kMaxPrecisionDigits + 7;++extern "C"+int _hs_ToPrecisionLength(void)+{+ return kToPrecisionLength;+}++static int copy(uint16_t *buf, const StringBuilder& builder, const char *cbuf)+{+ const int pos = builder.position();+ for (int i = 0; i < pos; i++)+ buf[i] = cbuf[i];+ 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;+ static DoubleToStringConverter converter(flags,+ "Infinity",+ "NaN",+ 'e',+ -6, 21,+ 6, 0);+ return converter;+}++static inline const DoubleToStringConverter& floatConverter(void)+{+ const int flags = DoubleToStringConverter::UNIQUE_ZERO;+ static DoubleToStringConverter converter(flags,+ "Infinity",+ "NaN",+ 'e',+ -6, 6,+ 6, 0);+ return converter;+}++extern "C"+int _hs_ToShortest(double value, char *buf)+{+ StringBuilder builder(buf, kToShortestLength);+ return defaultConverter().ToShortest(value, &builder)+ ? builder.position() : -1;+}++extern "C"+int _hs_ToShortestFloat(float value, char *buf)+{+ StringBuilder builder(buf, kToShortestLength);+ return floatConverter().ToShortestSingle(value, &builder)+ ? builder.position() : -1;+}++extern "C"+int _hs_Text_ToShortest(double value, uint16_t *buf)+{+ char cbuf[kToShortestLength];+ return copy(buf, cbuf, _hs_ToShortest(value, cbuf));+}++extern "C"+int _hs_Text_ToShortestFloat(float value, uint16_t *buf)+{+ char cbuf[kToShortestLength];+ return copy(buf, cbuf, _hs_ToShortestFloat(value, 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;+}++int _hs_ToFixedFloat(float value, char *buf, const int ndigits)+{+ StringBuilder builder(buf, kToFixedLength);+ return floatConverter().ToFixed(value, ndigits, &builder)+ ? builder.position() : -1;+}++extern "C"+int _hs_Text_ToFixed(double value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToFixedLength];+ return copy(buf, cbuf, _hs_ToFixed(value, cbuf, ndigits));+}++extern "C"+int _hs_Text_ToFixedFloat(float value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToFixedLength];+ return copy(buf, cbuf, _hs_ToFixedFloat(value, cbuf, ndigits));+}++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_ToExponentialFloat(float value, char *buf, const int ndigits)+{+ StringBuilder builder(buf, kToExponentialLength);+ return floatConverter().ToExponential(value, ndigits, &builder)+ ? builder.position() : -1;+}++extern "C"+int _hs_Text_ToExponential(double value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToExponentialLength];+ return copy(buf, cbuf, _hs_ToExponential(value, cbuf, ndigits));+}++extern "C"+int _hs_Text_ToExponentialFloat(float value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToExponentialLength];+ return copy(buf, cbuf, _hs_ToExponentialFloat(value, cbuf, ndigits));+}++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_ToPrecisionFloat(float value, char *buf, const int precision)+{+ StringBuilder builder(buf, kToPrecisionLength);+ return floatConverter().ToPrecision(value, precision, &builder)+ ? builder.position() : -1;+}++extern "C"+int _hs_Text_ToPrecision(double value, uint16_t *buf, const int precision)+{+ char cbuf[kToPrecisionLength];+ return copy(buf, cbuf, _hs_ToPrecision(value, cbuf, precision));+}++extern "C"+int _hs_Text_ToPrecisionFloat(float value, uint16_t *buf, const int precision)+{+ char cbuf[kToPrecisionLength];+ return copy(buf, cbuf, _hs_ToPrecisionFloat(value, cbuf, precision));+}
cbits/hs-double-conversion.cc view
@@ -1,4 +1,4 @@-#include "double-conversion.h"+#include "double-conversion/double-conversion.h" #include "hs-double-conversion.h" #include <stdio.h> @@ -67,6 +67,18 @@ return converter; } +static inline const DoubleToStringConverter& floatConverter(void)+{+ const int flags = DoubleToStringConverter::UNIQUE_ZERO;+ static DoubleToStringConverter converter(flags,+ "Infinity",+ "NaN",+ 'e',+ -6, 6,+ 6, 0);+ return converter;+}+ extern "C" int _hs_ToShortest(double value, char *buf) {@@ -76,6 +88,14 @@ } extern "C"+int _hs_ToShortestFloat(float value, char *buf)+{+ StringBuilder builder(buf, kToShortestLength);+ return floatConverter().ToShortestSingle(value, &builder)+ ? builder.position() : -1;+}++extern "C" int _hs_Text_ToShortest(double value, uint16_t *buf) { char cbuf[kToShortestLength];@@ -83,6 +103,13 @@ } extern "C"+int _hs_Text_ToShortestFloat(float value, uint16_t *buf)+{+ char cbuf[kToShortestLength];+ return copy(buf, cbuf, _hs_ToShortestFloat(value, cbuf));+}++extern "C" int _hs_ToFixed(double value, char *buf, const int ndigits) { StringBuilder builder(buf, kToFixedLength);@@ -90,6 +117,13 @@ ? builder.position() : -1; } +int _hs_ToFixedFloat(float value, char *buf, const int ndigits)+{+ StringBuilder builder(buf, kToFixedLength);+ return floatConverter().ToFixed(value, ndigits, &builder)+ ? builder.position() : -1;+}+ extern "C" int _hs_Text_ToFixed(double value, uint16_t *buf, const int ndigits) {@@ -98,6 +132,13 @@ } extern "C"+int _hs_Text_ToFixedFloat(float value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToFixedLength];+ return copy(buf, cbuf, _hs_ToFixedFloat(value, cbuf, ndigits));+}++extern "C" int _hs_ToExponential(double value, char *buf, const int ndigits) { StringBuilder builder(buf, kToExponentialLength);@@ -106,6 +147,14 @@ } extern "C"+int _hs_ToExponentialFloat(float value, char *buf, const int ndigits)+{+ StringBuilder builder(buf, kToExponentialLength);+ return floatConverter().ToExponential(value, ndigits, &builder)+ ? builder.position() : -1;+}++extern "C" int _hs_Text_ToExponential(double value, uint16_t *buf, const int ndigits) { char cbuf[kToExponentialLength];@@ -113,6 +162,13 @@ } extern "C"+int _hs_Text_ToExponentialFloat(float value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToExponentialLength];+ return copy(buf, cbuf, _hs_ToExponentialFloat(value, cbuf, ndigits));+}++extern "C" int _hs_ToPrecision(double value, char *buf, const int precision) { StringBuilder builder(buf, kToPrecisionLength);@@ -121,8 +177,23 @@ } extern "C"+int _hs_ToPrecisionFloat(float value, char *buf, const int precision)+{+ StringBuilder builder(buf, kToPrecisionLength);+ return floatConverter().ToPrecision(value, precision, &builder)+ ? builder.position() : -1;+}++extern "C" int _hs_Text_ToPrecision(double value, uint16_t *buf, const int precision) { char cbuf[kToPrecisionLength]; return copy(buf, cbuf, _hs_ToPrecision(value, cbuf, precision));+}++extern "C"+int _hs_Text_ToPrecisionFloat(float value, uint16_t *buf, const int precision)+{+ char cbuf[kToPrecisionLength];+ return copy(buf, cbuf, _hs_ToPrecisionFloat(value, cbuf, precision)); }
double-conversion.cabal view
@@ -1,31 +1,37 @@+cabal-version: 2.2 name: double-conversion-version: 2.0.2.0-license: BSD3+version: 2.0.5.0+license: BSD-2-Clause license-file: LICENSE-homepage: https://github.com/bos/double-conversion-bug-reports: https://github.com/bos/double-conversion/issues+homepage: https://github.com/haskell/double-conversion+bug-reports: https://github.com/haskell/double-conversion/issues category: Text author: Bryan O'Sullivan <bos@serpentine.com> maintainer: Bryan O'Sullivan <bos@serpentine.com> stability: experimental-synopsis: Fast conversion between double precision floating point and text-cabal-version: >= 1.8+synopsis: Fast conversion between single and double precision floating point and text build-type: Simple+tested-with: GHC ==9.0.2 || ==9.2.8 || ==9.4.7 || ==9.6.2 description:- A library that performs fast, accurate conversion between double- precision floating point and text.+ A library that performs fast, accurate conversion between + floating point and text. . This library is implemented as bindings to the C++ @double-conversion@ library written by Florian Loitsch at Google: <https://github.com/floitsch/double-conversion>. .+ Now it can convert single precision numbers, and also it can create + Builder, instead of bytestring or text. + . 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@.)+ The 'ByteString' versions are have very close speed to the 'Text' versions; .+ Builder versions (both for Text and Bytestring) are slower on single value,+ but they are much faster on large number of values + (up to 20x faster on list with 20000 doubles).+ . As a final note, be aware that the @bytestring-show@ package is about 50% slower than simply using 'show'. @@ -59,39 +65,60 @@ default: False manual: True +flag embedded_double_conversion+ description: embed the C++ double_conversion library+ default: True+ library- c-sources:- cbits/hs-double-conversion.cc- double-conversion/src/bignum.cc- double-conversion/src/bignum-dtoa.cc- double-conversion/src/cached-powers.cc- double-conversion/src/diy-fp.cc- double-conversion/src/double-conversion.cc- double-conversion/src/fast-dtoa.cc- double-conversion/src/fixed-dtoa.cc- double-conversion/src/strtod.cc+ if impl(ghc >= 9.4)+ build-depends: system-cxx-std-lib == 1.0 - if os(windows)- if arch(x86_64)+ elif os(darwin) || os(freebsd)+ extra-libraries: c+++ elif os(windows)+ if arch(x86_64) && impl(ghc < 8.6.5) extra-libraries: stdc++-6 gcc_s_seh-1- else+ elif arch(x86_64)+ extra-libraries: stdc++ gcc_s_seh-1+ elif impl(ghc >= 8.6.5)+ extra-libraries: stdc++ gcc_s_dw2-1+ else extra-libraries: stdc++-6 gcc_s_dw2-1 else- if os(darwin)- extra-libraries: c++- else- extra-libraries: stdc+++ extra-libraries: stdc++ + if flag(embedded_double_conversion)+ cxx-sources:+ cbits/hs-double-conversion-embed.cc++ double-conversion/src/bignum.cc+ double-conversion/src/bignum-dtoa.cc+ double-conversion/src/cached-powers.cc+ double-conversion/src/diy-fp.cc+ double-conversion/src/double-conversion.cc+ double-conversion/src/fast-dtoa.cc+ double-conversion/src/fixed-dtoa.cc+ double-conversion/src/strtod.cc+ include-dirs: double-conversion/src+ else+ extra-libraries: double-conversion+ cxx-sources:+ cbits/hs-double-conversion.cc+ include-dirs:- double-conversion/src include exposed-modules:+ Data.Double.Conversion.Convertable Data.Double.Conversion.ByteString Data.Double.Conversion.Text other-modules:- Data.Double.Conversion.FFI+ Data.Double.Conversion.Internal.FFI+ Data.Double.Conversion.Internal.ByteString+ Data.Double.Conversion.Internal.ByteStringBuilder+ Data.Double.Conversion.Internal.Text+ Data.Double.Conversion.Internal.TextBuilder build-depends: base == 4.*,@@ -100,13 +127,15 @@ text >= 0.11.0.8 if flag(developer)- ghc-options: -Werror+ ghc-options: -Werror ghc-prof-options: -auto-all else- cc-options: -DNDEBUG+ cc-options: -DNDEBUG - ghc-options: -Wall+ ghc-options: -Wall + default-language: Haskell2010+ test-suite tests type: exitcode-stdio-1.0 hs-source-dirs: tests@@ -122,11 +151,8 @@ test-framework-hunit, test-framework-quickcheck2, text+ default-language: Haskell2010 source-repository head type: git- location: https://github.com/bos/double-conversion--source-repository head- type: mercurial- location: https://bitbucket.org/bos/double-conversion+ location: https://github.com/haskell/double-conversion
double-conversion/CMakeLists.txt view
@@ -1,44 +1,34 @@-cmake_minimum_required(VERSION 2.8)-project(double-conversion)--# pick a version #-set(double-conversion_VERSION 2.0.1)-set(double-conversion_SOVERSION_MAJOR 1)-set(double-conversion_SOVERSION_MINOR 0)-set(double-conversion_SOVERSION_PATCH 0)-set(double-conversion_SOVERSION- ${double-conversion_SOVERSION_MAJOR}.${double-conversion_SOVERSION_MINOR}.${double-conversion_SOVERSION_PATCH})--# set paths for install -- empty initially-# Offer the user the choice of overriding the installation directories-set(INSTALL_BIN_DIR CACHE PATH "Installation directory for libraries")-set(INSTALL_LIB_DIR CACHE PATH "Installation directory for libraries")-set(INSTALL_INCLUDE_DIR CACHE PATH "Installation directory for include")-# set suffix for CMake files used for packaging-if(WIN32 AND NOT CYGWIN)- set(INSTALL_CMAKE_DIR CMake)-else()- set(INSTALL_CMAKE_DIR lib/CMake/double-conversion)-endif()+cmake_minimum_required(VERSION 3.0)+project(double-conversion VERSION 3.0.0) -# Make relative paths absolute (needed later)-foreach(p LIB BIN INCLUDE CMAKE)- set(var INSTALL_${p}_DIR)- if(NOT IS_ABSOLUTE "${${var}}")- set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")- endif()-endforeach()+set(headers+ double-conversion/bignum.h+ double-conversion/cached-powers.h+ double-conversion/diy-fp.h+ double-conversion/double-conversion.h+ double-conversion/fast-dtoa.h+ double-conversion/fixed-dtoa.h+ double-conversion/ieee.h+ double-conversion/strtod.h+ double-conversion/utils.h) -#-# set up include dirs-include_directories("${PROJECT_SOURCE_DIR}/src"- "${PROJECT_BINARY_DIR}"- )+add_library(double-conversion+ double-conversion/bignum.cc+ double-conversion/bignum-dtoa.cc+ double-conversion/cached-powers.cc+ double-conversion/diy-fp.cc+ double-conversion/double-conversion.cc+ double-conversion/fast-dtoa.cc+ double-conversion/fixed-dtoa.cc+ double-conversion/strtod.cc+ ${headers})+target_include_directories(+ double-conversion PUBLIC+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>) -# Add src subdirectory-add_subdirectory(src)+# pick a version #+set_property(TARGET double-conversion PROPERTY SOVERSION ${PROJECT_VERSION}) -# # set up testing if requested option(BUILD_TESTING "Build test programs" OFF) if(BUILD_TESTING)@@ -47,47 +37,75 @@ add_subdirectory(test) endif() -#-# mention the library target as export library-export(TARGETS double-conversion- FILE "${PROJECT_BINARY_DIR}/double-conversionLibraryDepends.cmake")+####+# Installation (https://github.com/forexample/package-example) -#-# set this build as an importable package-export(PACKAGE double-conversion)+# Layout. This works for all platforms:+# * <prefix>/lib/cmake/<PROJECT-NAME>+# * <prefix>/lib/+# * <prefix>/include/+set(config_install_dir "lib/cmake/${PROJECT_NAME}")+set(include_install_dir "include") -#-# make a cmake file -- in this case, all that needs defining-# is double-conversion_INCLUDE_DIRS-configure_file(double-conversionBuildTreeSettings.cmake.in- "${PROJECT_BINARY_DIR}/double-conversionBuildTreeSettings.cmake"- @ONLY)+set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") -#-# determine where include is relative to the CMake dir in-# in installed tree-file(RELATIVE_PATH CONF_REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}"- "${INSTALL_INCLUDE_DIR}")+# Configuration+set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")+set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")+set(targets_export_name "${PROJECT_NAME}Targets")+set(namespace "${PROJECT_NAME}::") -#-# sets up config to be used by CMake find_package-configure_file(double-conversionConfig.cmake.in- "${PROJECT_BINARY_DIR}/double-conversionConfig.cmake"- @ONLY)-#-# Export version # checked by find_package-configure_file(double-conversionConfigVersion.cmake.in- "${PROJECT_BINARY_DIR}/double-conversionConfigVersion.cmake"- @ONLY)-#-# install config files for find_package-install(FILES- "${PROJECT_BINARY_DIR}/double-conversionConfig.cmake"- "${PROJECT_BINARY_DIR}/double-conversionConfigVersion.cmake"- DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev)+# Include module with function 'write_basic_package_version_file'+include(CMakePackageConfigHelpers) +# Configure '<PROJECT-NAME>ConfigVersion.cmake'+# Note: PROJECT_VERSION is used as a VERSION+write_basic_package_version_file(+ "${version_config}" COMPATIBILITY SameMajorVersion+) -#-# generates install cmake files to find libraries in installation.-install(EXPORT double-conversionLibraryDepends DESTINATION- "${INSTALL_CMAKE_DIR}" COMPONENT dev)+# Configure '<PROJECT-NAME>Config.cmake'+# Use variables:+# * targets_export_name+# * PROJECT_NAME+configure_package_config_file(+ "cmake/Config.cmake.in"+ "${project_config}"+ INSTALL_DESTINATION "${config_install_dir}"+)++# Targets:+# * <prefix>/lib/libdouble-conversion.a+# * header location after install: <prefix>/include/double-conversion/*.h+# * headers can be included by C++ code `#include <double-conversion/*.h>`+install(+ TARGETS double-conversion+ EXPORT "${targets_export_name}"+ LIBRARY DESTINATION "lib"+ ARCHIVE DESTINATION "lib"+ RUNTIME DESTINATION "bin"+ INCLUDES DESTINATION "${include_install_dir}"+)++# Headers:+# * double-conversion/*.h -> <prefix>/include/double-conversion/*.h+install(+ FILES ${headers}+ DESTINATION "${include_install_dir}/double-conversion"+)++# Config+# * <prefix>/lib/cmake/double-conversion/double-conversionConfig.cmake+# * <prefix>/lib/cmake/double-conversion/double-conversionConfigVersion.cmake+install(+ FILES "${project_config}" "${version_config}"+ DESTINATION "${config_install_dir}"+)++# Config+# * <prefix>/lib/cmake/double-conversion/double-conversionTargets.cmake+install(+ EXPORT "${targets_export_name}"+ NAMESPACE "${namespace}"+ DESTINATION "${config_install_dir}"+)
double-conversion/Changelog view
@@ -1,3 +1,33 @@+2017-12-06:+ Renamed `DISALLOW_COPY_AND_ASSIGN` and `DISALLOW_IMPLICIT_CONSTRUCTORS`+ macros to `DC_DISALLOW_COPY_AND_ASSIGN` and+ `DC_DISALLOW_IMPLICIT_CONSTRUCTORS` to make it easier to integrate the+ library with other libraries that have similar macros.++2017-08-05:+ Tagged v3.0.0.+ Due to the directory rename switching to a new version number.+ The API for the library itself hasn't changed.++2017-03-04:+ Avoid negative shift. Fixes #41.++2016-11-17:+ Support RISC-V.+++2016-09-10:+ Add fPIC flag on x86_64 if the compiler supports it. Fixes #34.++2015 and 2016:+ Lots of improvements to the build system.++2015:+ Warning fixes.++2015-05-19:+ Rename 'src' directory to 'double-conversion'.+ 2014-03-08: Update version number for cmake. Support shared libraries with cmake.
double-conversion/SConstruct view
@@ -1,7 +1,7 @@ # vim:ft=python import os -double_conversion_sources = ['src/' + x for x in SConscript('src/SConscript')]+double_conversion_sources = ['double-conversion/' + x for x in SConscript('double-conversion/SConscript')] double_conversion_test_sources = ['test/cctest/' + x for x in SConscript('test/cctest/SConscript')] DESTDIR = ARGUMENTS.get('DESTDIR', '')@@ -9,7 +9,7 @@ lib = ARGUMENTS.get('libsuffix', 'lib') libdir = os.path.join(DESTDIR + prefix, lib) -env = Environment(CPPPATH='#/src', LIBS=['m', 'stdc++'],+env = Environment(CPPPATH='#', LIBS=['m', 'stdc++'], CXXFLAGS=ARGUMENTS.get('CXXFLAGS', '')) debug = ARGUMENTS.get('debug', 0) optimize = ARGUMENTS.get('optimize', 0)
double-conversion/test/cctest/cctest.h view
@@ -31,7 +31,7 @@ #include <stdio.h> #include <string.h> -#include "utils.h"+#include "double-conversion/utils.h" #ifndef TEST #define TEST(Name) \@@ -75,8 +75,11 @@ const char* value_source, const char* value) { if ((expected == NULL && value != NULL) ||- (expected != NULL && value == NULL) ||- (expected != NULL && value != NULL && strcmp(expected, value) != 0)) {+ (expected != NULL && value == NULL)) {+ abort();+ }++ if ((expected != NULL && value != NULL && strcmp(expected, value) != 0)) { printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n" "# Expected: %s\n" "# Found: %s\n",@@ -124,10 +127,10 @@ static int test_count(); static CcTest* last() { return last_; } CcTest* prev() { return prev_; }- const char* file() { return file_; }- const char* name() { return name_; }- const char* dependency() { return dependency_; }- bool enabled() { return enabled_; }+ const char* file() const { return file_; }+ const char* name() const { return name_; }+ const char* dependency() const { return dependency_; }+ bool enabled() const { return enabled_; } private: TestFunction* callback_; const char* file_;
double-conversion/test/cctest/gay-fixed.cc view
file too large to diff
double-conversion/test/cctest/gay-precision.cc view
file too large to diff
double-conversion/test/cctest/gay-shortest-single.cc view
@@ -28,7 +28,7 @@ // This file contains 100.000 decimal representations of random singles. They // have been generated using Gay's gdtoa to produce the shortest representation. -#include "utils.h"+#include "double-conversion/utils.h" #include "gay-shortest-single.h"
double-conversion/test/cctest/gay-shortest.cc view
file too large to diff
double-conversion/test/cctest/test-bignum-dtoa.cc view
@@ -27,15 +27,15 @@ #include <stdlib.h> -#include "bignum-dtoa.h"+#include "double-conversion/bignum-dtoa.h" #include "cctest.h" #include "gay-fixed.h" #include "gay-precision.h" #include "gay-shortest.h" #include "gay-shortest-single.h"-#include "ieee.h"-#include "utils.h"+#include "double-conversion/ieee.h"+#include "double-conversion/utils.h" using namespace double_conversion;
double-conversion/test/cctest/test-bignum.cc view
@@ -29,9 +29,9 @@ #include <string.h> -#include "bignum.h"+#include "double-conversion/bignum.h" #include "cctest.h"-#include "utils.h"+#include "double-conversion/utils.h" using namespace double_conversion; @@ -993,6 +993,7 @@ other.AssignUInt16(2); other.ShiftLeft(500); CHECK_EQ(5, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("0", buffer); bignum.AssignUInt16(11);
double-conversion/test/cctest/test-conversions.cc view
@@ -3,9 +3,9 @@ #include <string.h> #include "cctest.h"-#include "double-conversion.h"-#include "ieee.h"-#include "utils.h"+#include "double-conversion/double-conversion.h"+#include "double-conversion/ieee.h"+#include "double-conversion/utils.h" // DoubleToString is already tested in test-dtoa.cc. @@ -1804,6 +1804,18 @@ CHECK_EQ(0, processed); + flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK;++ CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 3);++ CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 3);++ CHECK_EQ(123.0, StrToD("123e-a", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 3);++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES | StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN | StringToDoubleConverter::ALLOW_TRAILING_SPACES |@@ -3184,10 +3196,10 @@ CHECK(all_used); CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used));- CHECK(all_used);+ CHECK_EQ(processed, 3); CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used));- CHECK(all_used);+ CHECK_EQ(processed, 3); { StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "NaN");@@ -4709,4 +4721,47 @@ Single::NaN(), &processed, &all_used)); CHECK(all_used);+}+++TEST(StringToDoubleCaseInsensitiveSpecialValues) {+ int processed = 0;++ int flags = StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY |+ StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES;++ // Use 1.0 as junk_string_value.+ StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "nan");++ CHECK_EQ(Double::NaN(), converter.StringToDouble("+nan", 4, &processed));+ CHECK_EQ(4, processed);++ CHECK_EQ(Double::NaN(), converter.StringToDouble("-nAN", 4, &processed));+ CHECK_EQ(4, processed);++ CHECK_EQ(Double::NaN(), converter.StringToDouble("nAN", 3, &processed));+ CHECK_EQ(3, processed);++ CHECK_EQ(Double::NaN(), converter.StringToDouble("nANabc", 6, &processed));+ CHECK_EQ(3, processed);++ CHECK_EQ(+Double::Infinity(),+ converter.StringToDouble("+Infinity", 9, &processed));+ CHECK_EQ(9, processed);++ CHECK_EQ(-Double::Infinity(),+ converter.StringToDouble("-INFinity", 9, &processed));+ CHECK_EQ(9, processed);++ CHECK_EQ(Double::Infinity(),+ converter.StringToDouble("infINITY", 8, &processed));+ CHECK_EQ(8, processed);++ CHECK_EQ(1.0, converter.StringToDouble("INF", 3, &processed));+ CHECK_EQ(0, processed);++ CHECK_EQ(1.0, converter.StringToDouble("+inf", 4, &processed));+ CHECK_EQ(0, processed); }
double-conversion/test/cctest/test-diy-fp.cc view
@@ -3,8 +3,8 @@ #include <stdlib.h> #include "cctest.h"-#include "diy-fp.h"-#include "utils.h"+#include "double-conversion/diy-fp.h"+#include "double-conversion/utils.h" using namespace double_conversion;
double-conversion/test/cctest/test-dtoa.cc view
@@ -27,14 +27,14 @@ #include <stdlib.h> -#include "double-conversion.h"+#include "double-conversion/double-conversion.h" #include "cctest.h" #include "gay-fixed.h" #include "gay-precision.h" #include "gay-shortest.h" #include "gay-shortest-single.h"-#include "ieee.h"+#include "double-conversion/ieee.h" using namespace double_conversion;
double-conversion/test/cctest/test-fast-dtoa.cc view
@@ -3,13 +3,13 @@ #include <stdlib.h> #include "cctest.h"-#include "diy-fp.h"-#include "fast-dtoa.h"+#include "double-conversion/diy-fp.h"+#include "double-conversion/fast-dtoa.h" #include "gay-precision.h" #include "gay-shortest.h" #include "gay-shortest-single.h"-#include "ieee.h"-#include "utils.h"+#include "double-conversion/ieee.h"+#include "double-conversion/utils.h" using namespace double_conversion;
double-conversion/test/cctest/test-fixed-dtoa.cc view
@@ -29,10 +29,10 @@ #include "cctest.h"-#include "fixed-dtoa.h"+#include "double-conversion/fixed-dtoa.h" #include "gay-fixed.h"-#include "ieee.h"-#include "utils.h"+#include "double-conversion/ieee.h"+#include "double-conversion/utils.h" using namespace double_conversion; @@ -485,6 +485,10 @@ buffer, &length, &point)); CHECK_EQ("1000000000000000128", buffer.start()); CHECK_EQ(19, point);++ CHECK(FastFixedDtoa(2.10861548515811875e+15, 17, buffer, &length, &point));+ CHECK_EQ("210861548515811875", buffer.start());+ CHECK_EQ(16, point); }
double-conversion/test/cctest/test-ieee.cc view
@@ -3,10 +3,9 @@ #include <stdlib.h> #include "cctest.h"-#include "diy-fp.h"-#include "ieee.h"-#include "utils.h"-#include "../../src/ieee.h"+#include "double-conversion/diy-fp.h"+#include "double-conversion/utils.h"+#include "double-conversion/ieee.h" using namespace double_conversion;
double-conversion/test/cctest/test-strtod.cc view
@@ -2,12 +2,12 @@ #include <stdlib.h> -#include "bignum.h"+#include "double-conversion/bignum.h" #include "cctest.h"-#include "diy-fp.h"-#include "ieee.h"-#include "strtod.h"-#include "utils.h"+#include "double-conversion/diy-fp.h"+#include "double-conversion/ieee.h"+#include "double-conversion/strtod.h"+#include "double-conversion/utils.h" using namespace double_conversion;
include/hs-double-conversion.h view
@@ -10,16 +10,24 @@ int _hs_ToShortestLength(void); int _hs_Text_ToShortest(double value, uint16_t *buf);+int _hs_Text_ToShortestFloat(float value, uint16_t *buf); int _hs_ToShortest(double value, char *buf);+int _hs_ToShortestFloat(float value, char *buf); int _hs_ToFixedLength(void); int _hs_Text_ToFixed(double value, uint16_t *buf, int ndigits);+int _hs_Text_ToFixedFloat(float value, uint16_t *buf, int ndigits); int _hs_ToFixed(double value, char *buf, int ndigits);+int _hs_ToFixedFloat(float value, char *buf, int ndigits); int _hs_ToExponentialLength(void); int _hs_Text_ToExponential(double value, uint16_t *buf, int ndigits);+int _hs_Text_ToExponentialFloat(float value, uint16_t *buf, int ndigits); int _hs_ToExponential(double value, char *buf, int ndigits);+int _hs_ToExponentialFloat(float value, char *buf, int ndigits); int _hs_ToPrecisionLength(void); int _hs_Text_ToPrecision(double value, uint16_t *buf, int ndigits);+int _hs_Text_ToPrecisionFloat(float value, uint16_t *buf, int ndigits); int _hs_ToPrecision(double value, char *buf, int ndigits);+int _hs_ToPrecisionFloat(float value, char *buf, int ndigits); #ifdef __cplusplus }
tests/Properties.hs view
@@ -1,8 +1,7 @@ import Test.Framework (Test, defaultMain, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import qualified Data.ByteString.Char8 as B-import qualified Data.Double.Conversion.ByteString as B-import qualified Data.Double.Conversion.Text as T+import qualified Data.Double.Conversion.Convertable as C import qualified Data.Text as T import qualified Regressions @@ -15,8 +14,8 @@ tests :: Test tests = testGroup "Properties" [- testProperty "b_shortest" $ shortest (B.unpack . B.toShortest)- , testProperty "t_shortest" $ shortest (T.unpack . T.toShortest)+ testProperty "b_shortest" $ shortest (B.unpack . C.toShortest)+ , testProperty "t_shortest" $ shortest (T.unpack . C.toShortest) ] main :: IO ()
tests/Regressions.hs view
@@ -3,7 +3,7 @@ tests ) where -import Data.Double.Conversion.Text (toShortest)+import Data.Double.Conversion.Convertable import Test.HUnit (Assertion, assertEqual) import Data.Text (unpack) import Numeric (showFFloat)@@ -12,7 +12,7 @@ toShortest_overflow :: Assertion toShortest_overflow = do- let val = -2.9658956854023756e-5+ let val = -2.9658956854023756e-5 :: Double assertEqual "rendering a long number doesn't crash" (showFFloat Nothing val "") (unpack (toShortest val))