double-conversion 2.0.4.1 → 2.0.4.2
raw patch · 11 files changed
+288/−61 lines, 11 filesdep +system-cxx-std-libdep ~basedep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: system-cxx-std-lib
Dependency ranges changed: base, bytestring
API changes (from Hackage documentation)
Files
- Data/Double/Conversion/ByteString.hs +3/−0
- Data/Double/Conversion/Convertable.hs +10/−6
- Data/Double/Conversion/Internal/ByteString.hs +1/−1
- Data/Double/Conversion/Internal/ByteStringBuilder.hs +1/−4
- Data/Double/Conversion/Internal/Text.hs +2/−2
- Data/Double/Conversion/Internal/TextBuilder.hs +15/−9
- Data/Double/Conversion/Text.hs +3/−0
- benchmarks/Benchmarks.hs +10/−10
- cbits/hs-double-conversion-embed.cc +199/−0
- cbits/hs-double-conversion.cc +1/−1
- double-conversion.cabal +43/−28
Data/Double/Conversion/ByteString.hs view
@@ -11,6 +11,9 @@ -- 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. --
Data/Double/Conversion/Convertable.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE DefaultSignatures, InstanceSigs, MagicHash, MultiParamTypeClasses,- TypeFamilies #-}+ TypeFamilies, TypeOperators #-} -- | -- Module : Data.Double.Conversion.Convertable@@ -27,7 +27,7 @@ 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 cen be converted, using double-conversion library+-- | 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. --@@ -51,11 +51,15 @@ -- Compute the shortest string of digits that correctly represent -- the input number. ----- Conversion to text is twice faster than conversion to bytestring -- Conversion to text via Builder (both in the in case of bytestring and text) in case of single number--- is much slower, than to text or bytestring directly. (2-3x)--- But conversion large amount of numbers to text via Builder is much faster than directly (up to 50x).--- Conversion to text via text builder is a little slower, then via bytestring builder+-- 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
Data/Double/Conversion/Internal/ByteString.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilies, TypeOperators #-} -- | -- Module : Data.Double.Conversion.ByteString
Data/Double/Conversion/Internal/ByteStringBuilder.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilies, TypeOperators #-} -- | -- Module : Data.Double.Conversion.ByteStringBuilder@@ -11,9 +11,6 @@ -- -- Fast, efficient support for converting between double precision -- floating point values and bytestring builder.---- This functions are much slower on the single value, but also it is much faster in conversting big set of--- numbers, than bytestring functions. See benchmark. module Data.Double.Conversion.Internal.ByteStringBuilder (convert
Data/Double/Conversion/Internal/Text.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies, BangPatterns #-}+{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies, BangPatterns, TypeOperators #-} -- | -- Module : Data.Double.Conversion.Text@@ -52,7 +52,7 @@ #endif size <- unsafeIOToST $ act (realToFrac val) ma when (size == -1) .- fail $ "Data.Double.Conversion.Text." ++ func +++ 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
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies #-}+{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies, TypeOperators #-} -- | -- Module : Data.Double.Conversion.TextBuilder -- Copyright : (c) 2011 MailRank, Inc.@@ -28,21 +28,27 @@ import Data.Text.Internal.Builder (Builder, writeN) import Foreign.C.Types (CDouble, CFloat, CInt) import GHC.Prim (MutableByteArray#)+import Control.Monad.ST (runST) --- | Not implemented yet 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)-convert func len act val = writeN (fromIntegral len) $ \(A.MutableByteArray maBa) _ -> do+ mTempArr@(A.MutableByteArray tempMArr) <- A.new (fromIntegral len) #else-convert func len act val = writeN (fromIntegral len) $ \(A.MArray maBa) _ -> do+ mTempArr@(A.MArray tempMArr) <- A.new (fromIntegral len) #endif- size <- unsafeIOToST $ act (realToFrac val) maBa- when (size == -1) .- fail $ "Data.Double.Conversion.Text." ++ func ++- ": conversion failed (invalid precision requested)"- return ()+ 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
@@ -13,6 +13,9 @@ -- 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. --
benchmarks/Benchmarks.hs view
@@ -18,34 +18,34 @@ 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+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+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+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+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+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+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+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+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+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+testFuncBuilderDefaultFloat = \list -> BSL.toStrict $ BB.toLazyByteString $ foldr (\x y -> (BB.floatDec x <> ", ") <> y) mempty list main = defaultMain [
+ 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>
double-conversion.cabal view
@@ -1,15 +1,15 @@+cabal-version: 2.2 name: double-conversion-version: 2.0.4.1-license: BSD3+version: 2.0.4.2+license: BSD-3-Clause license-file: LICENSE-homepage: https://github.com/Haskell-mouse/double-conversion-bug-reports: https://github.com/Haskell-mouse/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 single and double precision floating point and text-cabal-version: >= 1.10 build-type: Simple description: A library that performs fast, accurate conversion between @@ -25,12 +25,11 @@ 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 are slower on single value, but they are much faster on large number of values - (up to 50x faster on list with 20000 doubles). + 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'.@@ -65,31 +64,47 @@ 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)+ c-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+ c-sources:+ cbits/hs-double-conversion.cc+ include-dirs:- double-conversion/src include exposed-modules: