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
@@ -1,3 +1,5 @@
+{-# LANGUAGE TypeFamilies #-}
+
 -- |
 -- Module      : Data.Double.Conversion.ByteString
 -- Copyright   : (c) 2011 MailRank, Inc.
@@ -16,57 +18,23 @@
 -- 'ByteString' values via @malloc@.)
 
 module Data.Double.Conversion.ByteString
-    (
-      toExponential
-    , toFixed
-    , toPrecision
-    , toShortest
+    ( convert
     ) 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 Data.Double.Conversion.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)
 
--- | Compute a representation in exponential format with the requested
--- number of digits after the decimal point. The last emitted digit is
--- rounded.  If -1 digits are requested, then the shortest exponential
--- representation is computed.
-toExponential :: Int -> Double -> ByteString
-toExponential ndigits = convert "toExponential" len $ \val mba ->
-                        c_ToExponential val mba (fromIntegral ndigits)
-  where len = c_ToExponentialLength
-        {-# NOINLINE len #-}
-
--- | Compute a decimal representation with a fixed number of digits
--- after the decimal point. The last emitted digit is rounded.
-toFixed :: Int -> Double -> ByteString
-toFixed ndigits = convert "toFixed" len $ \val mba ->
-                  c_ToFixed val mba (fromIntegral ndigits)
-  where len = c_ToFixedLength
-        {-# NOINLINE len #-}
-
--- | Compute the shortest string of digits that correctly represent
--- the input number.
-toShortest :: Double -> ByteString
-toShortest = convert "toShortest" len c_ToShortest
-  where len = c_ToShortestLength
-        {-# NOINLINE len #-}
-
--- | Compute @precision@ leading digits of the given value either in
--- exponential or decimal format. The last computed digit is rounded.
-toPrecision :: Int -> Double -> ByteString
-toPrecision ndigits = convert "toPrecision" len $ \val mba ->
-                      c_ToPrecision val mba (fromIntegral ndigits)
-  where len = c_ToPrecisionLength
-        {-# NOINLINE len #-}
-
-convert :: String -> CInt -> (CDouble -> Ptr Word8 -> IO CInt)
-        -> Double -> ByteString
+convert :: (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)
diff --git a/Data/Double/Conversion/ByteStringBuilder.hs b/Data/Double/Conversion/ByteStringBuilder.hs
new file mode 100644
--- /dev/null
+++ b/Data/Double/Conversion/ByteStringBuilder.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE TypeFamilies #-}
+
+-- |
+-- 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.
+
+-- 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.ByteStringBuilder
+    (convert
+    ) where
+
+import Control.Monad (when)
+
+import Data.ByteString.Builder.Prim.Internal (BoundedPrim, boudedPrim)
+
+import Data.Double.Conversion.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))
diff --git a/Data/Double/Conversion/Convertable.hs b/Data/Double/Conversion/Convertable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Double/Conversion/Convertable.hs
@@ -0,0 +1,292 @@
+{-# LANGUAGE DefaultSignatures, InstanceSigs, MagicHash, MultiParamTypeClasses,
+             TypeFamilies #-}
+
+-- |
+-- 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.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.ByteString as CB (convert)
+import qualified Data.Double.Conversion.ByteStringBuilder as CBB (convert)
+import qualified Data.Double.Conversion.Text as CT (convert)
+import qualified Data.Double.Conversion.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
+--
+-- 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 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
+
+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 #-}
diff --git a/Data/Double/Conversion/FFI.hs b/Data/Double/Conversion/FFI.hs
--- a/Data/Double/Conversion/FFI.hs
+++ b/Data/Double/Conversion/FFI.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE CPP, ForeignFunctionInterface, MagicHash, UnliftedFFITypes #-}
+{-# LANGUAGE CPP, ForeignFunctionInterface, MagicHash, TypeFamilies,
+             UnliftedFFITypes #-}
 
 -- |
 -- Module      : Data.Double.Conversion.FFI
@@ -9,34 +10,48 @@
 -- Stability   : experimental
 -- Portability : GHC
 --
--- FFI interface support for converting between double precision
+-- FFI interface support for converting between
 -- floating point values and text.
 
 module Data.Double.Conversion.FFI
     (
-      c_Text_ToExponential
+      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), CInt(CInt))
+import Foreign.C.Types (CDouble(CDouble), CFloat(CFloat), CInt(CInt))
 #else
-import Foreign.C.Types (CDouble, CInt)
+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
 
@@ -46,15 +61,27 @@
 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_Text_ToShortestFloat"
+    c_Text_ToShortestFloat :: CFloat -> MutableByteArray# s -> 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_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_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
 
@@ -64,6 +91,12 @@
 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_Text_ToExponentialFloat"
+    c_Text_ToExponentialFloat :: CFloat -> MutableByteArray# s -> 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
 
@@ -72,3 +105,9 @@
 
 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_Text_ToPrecisionFloat"
+    c_Text_ToPrecisionFloat :: CFloat -> MutableByteArray# s -> CInt -> IO CInt
+
+foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecisionFloat"
+    c_ToPrecisionFloat :: CFloat -> Ptr Word8 -> CInt -> IO CInt
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
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, MagicHash, Rank2Types #-}
+{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies #-}
 
 -- |
 -- Module      : Data.Double.Conversion.Text
@@ -17,10 +17,7 @@
 
 module Data.Double.Conversion.Text
     (
-      toExponential
-    , toFixed
-    , toPrecision
-    , toShortest
+      convert
     ) where
 
 import Control.Monad (when)
@@ -29,51 +26,23 @@
 #else
 import Control.Monad.ST (unsafeIOToST)
 #endif
-import Control.Monad.ST (runST)
-import Data.Double.Conversion.FFI
+import Control.Monad.ST (ST, runST)
+import Data.Double.Conversion.FFI (ForeignFloating)
+import qualified Data.Text.Array as A
 import Data.Text.Internal (Text(Text))
-import Foreign.C.Types (CDouble, CInt)
+import Foreign.C.Types (CDouble, CFloat, CInt)
 import GHC.Prim (MutableByteArray#)
-import qualified Data.Text.Array as A
 
--- | Compute a representation in exponential format with the requested
--- number of digits after the decimal point. The last emitted digit is
--- rounded.  If -1 digits are requested, then the shortest exponential
--- representation is computed.
-toExponential :: Int -> Double -> Text
-toExponential ndigits = convert "toExponential" len $ \val mba ->
-                        c_Text_ToExponential val mba (fromIntegral ndigits)
-  where len = c_ToExponentialLength
-        {-# NOINLINE len #-}
 
--- | Compute a decimal representation with a fixed number of digits
--- after the decimal point. The last emitted digit is rounded.
-toFixed :: Int -> Double -> Text
-toFixed ndigits = convert "toFixed" len $ \val mba ->
-                  c_Text_ToFixed val mba (fromIntegral ndigits)
-  where len = c_ToFixedLength
-        {-# NOINLINE len #-}
-
--- | Compute the shortest string of digits that correctly represent
--- the input number.
-toShortest :: Double -> Text
-toShortest = convert "toShortest" len c_Text_ToShortest
-  where len = c_ToShortestLength
-        {-# NOINLINE len #-}
-
--- | Compute @precision@ leading digits of the given value either in
--- exponential or decimal format. The last computed digit is rounded.
-toPrecision :: Int -> Double -> Text
-toPrecision ndigits = convert "toPrecision" len $ \val mba ->
-                      c_Text_ToPrecision val mba (fromIntegral ndigits)
-  where len = c_ToPrecisionLength
-        {-# NOINLINE len #-}
-
-convert :: String -> CInt
-        -> (forall s. CDouble -> MutableByteArray# s -> IO CInt)
-        -> Double -> Text
+convert :: (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)
       size <- unsafeIOToST $ act (realToFrac val) (A.maBA buf)
diff --git a/Data/Double/Conversion/TextBuilder.hs b/Data/Double/Conversion/TextBuilder.hs
new file mode 100644
--- /dev/null
+++ b/Data/Double/Conversion/TextBuilder.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE CPP, MagicHash, Rank2Types, TypeFamilies #-}
+-- |
+-- 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.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.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#)
+
+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 = writeN (fromIntegral len) $ \(A.MArray maBa) _ -> do
+    size <- unsafeIOToST $ act (realToFrac val) maBa
+    when (size == -1) .
+        fail $ "Data.Double.Conversion.Text." ++ func ++
+               ": conversion failed (invalid precision requested)"
+    return ()
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -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!
 
diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs
--- a/benchmarks/Benchmarks.hs
+++ b/benchmarks/Benchmarks.hs
@@ -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
diff --git a/benchmarks/double-conversion-benchmarks.cabal b/benchmarks/double-conversion-benchmarks.cabal
--- a/benchmarks/double-conversion-benchmarks.cabal
+++ b/benchmarks/double-conversion-benchmarks.cabal
@@ -10,6 +10,7 @@
 
   build-depends:
     base,
+    bytestring, 
     bytestring-show,
     criterion >= 0.5.0.10,
     double-conversion,
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
@@ -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));
 }
diff --git a/double-conversion.cabal b/double-conversion.cabal
--- a/double-conversion.cabal
+++ b/double-conversion.cabal
@@ -1,24 +1,27 @@
 name:           double-conversion
-version:        2.0.2.0
+version:        2.0.3.0
 license:        BSD3
 license-file:   LICENSE
-homepage:       https://github.com/bos/double-conversion
-bug-reports:    https://github.com/bos/double-conversion/issues
+homepage:       https://github.com/Haskell-mouse/double-conversion
+bug-reports:    https://github.com/Haskell-mouse/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
+cabal-version:  >= 1.10
 build-type:     Simple
 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.
     .
@@ -26,6 +29,9 @@
     roughly half the speed.  (This seems to be due to the cost of
     allocating 'ByteString' values via @malloc@.)
     .
+    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).  
+    .
     As a final note, be aware that the @bytestring-show@ package is
     about 50% slower than simply using 'show'.
 
@@ -87,11 +93,14 @@
     include
 
   exposed-modules:
-    Data.Double.Conversion.ByteString
-    Data.Double.Conversion.Text
+    Data.Double.Conversion.Convertable
 
   other-modules:
     Data.Double.Conversion.FFI
+    Data.Double.Conversion.ByteString
+    Data.Double.Conversion.ByteStringBuilder
+    Data.Double.Conversion.Text
+    Data.Double.Conversion.TextBuilder
 
   build-depends:
     base == 4.*,
@@ -100,13 +109,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 +133,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-mouse/double-conversion
diff --git a/double-conversion/CMakeLists.txt b/double-conversion/CMakeLists.txt
--- a/double-conversion/CMakeLists.txt
+++ b/double-conversion/CMakeLists.txt
@@ -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}"
+)
diff --git a/double-conversion/Changelog b/double-conversion/Changelog
--- a/double-conversion/Changelog
+++ b/double-conversion/Changelog
@@ -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.
diff --git a/double-conversion/SConstruct b/double-conversion/SConstruct
--- a/double-conversion/SConstruct
+++ b/double-conversion/SConstruct
@@ -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)
diff --git a/double-conversion/test/cctest/cctest.h b/double-conversion/test/cctest/cctest.h
--- a/double-conversion/test/cctest/cctest.h
+++ b/double-conversion/test/cctest/cctest.h
@@ -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_;
diff --git a/double-conversion/test/cctest/gay-fixed.cc b/double-conversion/test/cctest/gay-fixed.cc
# file too large to diff: double-conversion/test/cctest/gay-fixed.cc
diff --git a/double-conversion/test/cctest/gay-precision.cc b/double-conversion/test/cctest/gay-precision.cc
# file too large to diff: double-conversion/test/cctest/gay-precision.cc
diff --git a/double-conversion/test/cctest/gay-shortest-single.cc b/double-conversion/test/cctest/gay-shortest-single.cc
--- a/double-conversion/test/cctest/gay-shortest-single.cc
+++ b/double-conversion/test/cctest/gay-shortest-single.cc
@@ -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"
 
diff --git a/double-conversion/test/cctest/gay-shortest.cc b/double-conversion/test/cctest/gay-shortest.cc
# file too large to diff: double-conversion/test/cctest/gay-shortest.cc
diff --git a/double-conversion/test/cctest/test-bignum-dtoa.cc b/double-conversion/test/cctest/test-bignum-dtoa.cc
--- a/double-conversion/test/cctest/test-bignum-dtoa.cc
+++ b/double-conversion/test/cctest/test-bignum-dtoa.cc
@@ -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;
 
diff --git a/double-conversion/test/cctest/test-bignum.cc b/double-conversion/test/cctest/test-bignum.cc
--- a/double-conversion/test/cctest/test-bignum.cc
+++ b/double-conversion/test/cctest/test-bignum.cc
@@ -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);
diff --git a/double-conversion/test/cctest/test-conversions.cc b/double-conversion/test/cctest/test-conversions.cc
--- a/double-conversion/test/cctest/test-conversions.cc
+++ b/double-conversion/test/cctest/test-conversions.cc
@@ -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);
 }
diff --git a/double-conversion/test/cctest/test-diy-fp.cc b/double-conversion/test/cctest/test-diy-fp.cc
--- a/double-conversion/test/cctest/test-diy-fp.cc
+++ b/double-conversion/test/cctest/test-diy-fp.cc
@@ -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;
diff --git a/double-conversion/test/cctest/test-dtoa.cc b/double-conversion/test/cctest/test-dtoa.cc
--- a/double-conversion/test/cctest/test-dtoa.cc
+++ b/double-conversion/test/cctest/test-dtoa.cc
@@ -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;
diff --git a/double-conversion/test/cctest/test-fast-dtoa.cc b/double-conversion/test/cctest/test-fast-dtoa.cc
--- a/double-conversion/test/cctest/test-fast-dtoa.cc
+++ b/double-conversion/test/cctest/test-fast-dtoa.cc
@@ -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;
 
diff --git a/double-conversion/test/cctest/test-fixed-dtoa.cc b/double-conversion/test/cctest/test-fixed-dtoa.cc
--- a/double-conversion/test/cctest/test-fixed-dtoa.cc
+++ b/double-conversion/test/cctest/test-fixed-dtoa.cc
@@ -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);
 }
 
 
diff --git a/double-conversion/test/cctest/test-ieee.cc b/double-conversion/test/cctest/test-ieee.cc
--- a/double-conversion/test/cctest/test-ieee.cc
+++ b/double-conversion/test/cctest/test-ieee.cc
@@ -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;
diff --git a/double-conversion/test/cctest/test-strtod.cc b/double-conversion/test/cctest/test-strtod.cc
--- a/double-conversion/test/cctest/test-strtod.cc
+++ b/double-conversion/test/cctest/test-strtod.cc
@@ -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;
 
diff --git a/include/hs-double-conversion.h b/include/hs-double-conversion.h
--- a/include/hs-double-conversion.h
+++ b/include/hs-double-conversion.h
@@ -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
 }
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -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.FP.Conversion.Convertable as B
 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 . toShortest)
+  , testProperty "t_shortest" $ shortest (T.unpack . toShortest)
   ]
 
 main :: IO ()
diff --git a/tests/Regressions.hs b/tests/Regressions.hs
--- a/tests/Regressions.hs
+++ b/tests/Regressions.hs
@@ -3,7 +3,7 @@
       tests
     ) where
 
-import Data.Double.Conversion.Text (toShortest)
+import Data.FP.Conversion.Convertable
 import Test.HUnit (Assertion, assertEqual)
 import Data.Text (unpack)
 import Numeric (showFFloat)
