diff --git a/Data/Double/Conversion/ByteString.hs b/Data/Double/Conversion/ByteString.hs
--- a/Data/Double/Conversion/ByteString.hs
+++ b/Data/Double/Conversion/ByteString.hs
@@ -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.
 --
diff --git a/Data/Double/Conversion/Convertable.hs b/Data/Double/Conversion/Convertable.hs
--- a/Data/Double/Conversion/Convertable.hs
+++ b/Data/Double/Conversion/Convertable.hs
@@ -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
diff --git a/Data/Double/Conversion/Internal/ByteString.hs b/Data/Double/Conversion/Internal/ByteString.hs
--- a/Data/Double/Conversion/Internal/ByteString.hs
+++ b/Data/Double/Conversion/Internal/ByteString.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeFamilies, TypeOperators #-}
 
 -- |
 -- Module      : Data.Double.Conversion.ByteString
diff --git a/Data/Double/Conversion/Internal/ByteStringBuilder.hs b/Data/Double/Conversion/Internal/ByteStringBuilder.hs
--- a/Data/Double/Conversion/Internal/ByteStringBuilder.hs
+++ b/Data/Double/Conversion/Internal/ByteStringBuilder.hs
@@ -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
diff --git a/Data/Double/Conversion/Internal/Text.hs b/Data/Double/Conversion/Internal/Text.hs
--- a/Data/Double/Conversion/Internal/Text.hs
+++ b/Data/Double/Conversion/Internal/Text.hs
@@ -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)
diff --git a/Data/Double/Conversion/Internal/TextBuilder.hs b/Data/Double/Conversion/Internal/TextBuilder.hs
--- a/Data/Double/Conversion/Internal/TextBuilder.hs
+++ b/Data/Double/Conversion/Internal/TextBuilder.hs
@@ -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
diff --git a/Data/Double/Conversion/Text.hs b/Data/Double/Conversion/Text.hs
--- a/Data/Double/Conversion/Text.hs
+++ b/Data/Double/Conversion/Text.hs
@@ -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.
 --
diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs
--- a/benchmarks/Benchmarks.hs
+++ b/benchmarks/Benchmarks.hs
@@ -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 [
diff --git a/cbits/hs-double-conversion-embed.cc b/cbits/hs-double-conversion-embed.cc
new file mode 100644
--- /dev/null
+++ b/cbits/hs-double-conversion-embed.cc
@@ -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));
+}
diff --git a/cbits/hs-double-conversion.cc b/cbits/hs-double-conversion.cc
--- a/cbits/hs-double-conversion.cc
+++ b/cbits/hs-double-conversion.cc
@@ -1,4 +1,4 @@
-#include "double-conversion.h"
+#include "double-conversion/double-conversion.h"
 #include "hs-double-conversion.h"
 #include <stdio.h>
 
diff --git a/double-conversion.cabal b/double-conversion.cabal
--- a/double-conversion.cabal
+++ b/double-conversion.cabal
@@ -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:
