diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,47 @@
+# fast-digits [![Build Status](https://travis-ci.org/Bodigrim/fast-digits.svg)](https://travis-ci.org/Bodigrim/fast-digits) [![Hackage](http://img.shields.io/hackage/v/fast-digits.svg)](https://hackage.haskell.org/package/fast-digits) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/fast-digits/badge)](https://matrix.hackage.haskell.org/package/fast-digits) [![Stackage LTS](http://stackage.org/package/fast-digits/badge/lts)](http://stackage.org/lts/package/fast-digits) [![Stackage Nightly](http://stackage.org/package/fast-digits/badge/nightly)](http://stackage.org/nightly/package/fast-digits)
+
+The fastest Haskell library to split integers into digits.
+It is both asymptotically (O(n<sup>1.4</sup>) vs. O(n<sup>2</sup>))
+and practically (2x-40x for typical inputs)
+faster than [Data.Digits](https://hackage.haskell.org/package/digits).
+
+Here are some benchmarks:
+
+```
+> cabal bench
+shortInt/FastDigits  base 2              mean 6.429 ms  ( +- 465.7 μs  )
+shortInt/Data.Digits base 2              mean 50.08 ms  ( +- 1.848 ms  )
+
+shortInt/FastDigits  base 10             mean 4.288 ms  ( +- 217.1 μs  )
+shortInt/Data.Digits base 10             mean 15.62 ms  ( +- 540.1 μs  )
+
+shortInt/FastDigits  base 10^5           mean 1.142 ms  ( +- 50.09 μs  )
+shortInt/Data.Digits base 10^5           mean 3.962 ms  ( +- 269.1 μs  )
+
+shortInt/FastDigits  base 10^9           mean 963.8 μs  ( +- 46.13 μs  )
+shortInt/Data.Digits base 10^9           mean 3.052 ms  ( +- 238.5 μs  )
+
+mediumInt/FastDigits  base 2             mean 1.213 ms  ( +- 185.0 μs  )
+mediumInt/Data.Digits base 2             mean 12.41 ms  ( +- 3.417 ms  )
+
+mediumInt/FastDigits  base 10            mean 689.3 μs  ( +- 32.43 μs  )
+mediumInt/Data.Digits base 10            mean 3.271 ms  ( +- 137.3 μs  )
+
+mediumInt/FastDigits  base 10^5          mean 220.1 μs  ( +- 11.30 μs  )
+mediumInt/Data.Digits base 10^5          mean 711.1 μs  ( +- 67.31 μs  )
+
+mediumInt/FastDigits  base 10^9          mean 156.0 μs  ( +- 9.115 μs  )
+mediumInt/Data.Digits base 10^9          mean 407.9 μs  ( +- 19.58 μs  )
+
+longInt/FastDigits  base 2               mean 3.515 ms  ( +- 189.7 μs  )
+longInt/Data.Digits base 2               mean 183.2 ms  ( +- 4.564 ms  )
+
+longInt/FastDigits  base 10              mean 2.164 ms  ( +- 134.7 μs  )
+longInt/Data.Digits base 10              mean 55.45 ms  ( +- 946.7 μs  )
+
+longInt/FastDigits  base 10^5            mean 1.467 ms  ( +- 60.49 μs  )
+longInt/Data.Digits base 10^5            mean 11.09 ms  ( +- 347.0 μs  )
+
+longInt/FastDigits  base 10^9            mean 1.242 ms  ( +- 52.92 μs  )
+longInt/Data.Digits base 10^9            mean 6.181 ms  ( +- 226.1 μs  )
+```
diff --git a/bench/Bench.hs b/bench/Bench.hs
--- a/bench/Bench.hs
+++ b/bench/Bench.hs
@@ -1,6 +1,6 @@
 module Main where
 
-import Criterion.Main
+import Gauge.Main
 
 import qualified Data.Digits as D
 
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,15 @@
+# 0.3.0.0
+
+* Hide `Data.FastDigits.Internal`.
+
+# 0.2.1.0
+
+* Fix x32 build.
+
+# 0.2.0.0
+
+* Performance improvements.
+
+# 0.1.0.0
+
+* Initial release.
diff --git a/fast-digits.cabal b/fast-digits.cabal
--- a/fast-digits.cabal
+++ b/fast-digits.cabal
@@ -1,53 +1,75 @@
-name:                fast-digits
-version:             0.2.1.0
-synopsis:            The fast library for integer-to-digits conversion.
-description:         Convert an integer to digits and back.
-                     Usually this library is twice as fast as "Data.Digits".
-                     For small bases and long numbers it may be up to 40 times faster.
-homepage:            https://github.com/Bodigrim/fast-digits
-license:             GPL-3
-license-file:        LICENSE
-author:              Andrew Lelechenko
-maintainer:          andrew.lelechenko@gmail.com
-category:            Data
-build-type:          Simple
-cabal-version:       >=1.10
+name: fast-digits
+version: 0.3.0.0
+license: GPL-3
+license-file: LICENSE
+maintainer: andrew.lelechenko@gmail.com
+author: Andrew Lelechenko
+homepage: https://github.com/Bodigrim/fast-digits
+synopsis: Integer-to-digits conversion.
+description:
+  Convert an integer to digits and back.
+  This library is both asymptotically (O(n^1.4) vs. O(n^2))
+  and practically (2x-40x for typical inputs)
+  faster than "Data.Digits".
+category: Data
+build-type: Simple
+cabal-version: 2.0
+extra-source-files:
+  changelog.md
+  README.md
+tested-with:
+  GHC ==7.10.3 GHC ==8.0.2 GHC ==8.2.2 GHC ==8.4.4 GHC ==8.6.5 GHC ==8.8.2
 
 source-repository head
-  type:     git
+  type: git
   location: git://github.com/Bodigrim/fast-digits.git
 
 library
-  exposed-modules:       Data.FastDigits
-                       , Data.FastDigits.Internal
-  build-depends:         base >=4.8 && < 5
-                       , integer-gmp >=1.0
-  hs-source-dirs:      src
-  default-language:    Haskell2010
-  ghc-options:         -Wall
+  exposed-modules:
+    Data.FastDigits
+  hs-source-dirs: src
+  default-language: Haskell2010
+  ghc-options: -Wall
+  build-depends:
+    base >=4.8 && <5,
+    integer-gmp >=1.0,
+    fast-digits-internal
 
+library fast-digits-internal
+  exposed-modules:
+    Data.FastDigits.Internal
+  hs-source-dirs: src-internal
+  default-language: Haskell2010
+  ghc-options: -Wall
+  build-depends:
+    base >=4.8 && <5,
+    integer-gmp >=1.0
+
 test-suite tests
-  type:                exitcode-stdio-1.0
-  main-is:             Tests.hs
-  build-depends:         base
-                       , tasty
-                       , tasty-quickcheck
-                       , tasty-smallcheck
-                       , QuickCheck
-                       , smallcheck
-                       , digits
-                       , fast-digits
-  hs-source-dirs:      tests
-  default-language:    Haskell2010
-  ghc-options:         -Wall
+  type: exitcode-stdio-1.0
+  main-is: Tests.hs
+  hs-source-dirs: tests
+  default-language: Haskell2010
+  ghc-options: -Wall
+  build-depends:
+    base,
+    tasty,
+    tasty-quickcheck,
+    tasty-smallcheck,
+    QuickCheck,
+    smallcheck,
+    digits,
+    fast-digits,
+    fast-digits-internal
 
 benchmark bench
-  type:                exitcode-stdio-1.0
-  main-is:             Bench.hs
-  hs-source-dirs:      bench
-  build-depends:         base
-                       , criterion
-                       , digits
-                       , fast-digits
-  default-language:    Haskell2010
-  ghc-options:         -O2
+  type: exitcode-stdio-1.0
+  main-is: Bench.hs
+  hs-source-dirs: bench
+  default-language: Haskell2010
+  ghc-options: -O2
+  build-depends:
+    base,
+    digits,
+    fast-digits,
+    gauge
diff --git a/src-internal/Data/FastDigits/Internal.hs b/src-internal/Data/FastDigits/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src-internal/Data/FastDigits/Internal.hs
@@ -0,0 +1,53 @@
+{-|
+Module      : Data.FastDigits.Internal
+Copyright   : (c) Andrew Lelechenko, 2015-2016
+License     : GPL-3
+Maintainer  : andrew.lelechenko@gmail.com
+Stability   : experimental
+
+-}
+
+{-# LANGUAGE CPP           #-}
+{-# LANGUAGE MagicHash     #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+{-# OPTIONS_GHC -fno-warn-type-defaults  #-}
+{-# OPTIONS_GHC -O2                      #-}
+{-# OPTIONS_GHC -optc-O3                 #-}
+
+module Data.FastDigits.Internal
+  ( selectPower
+  , selectPower'
+  ) where
+
+import GHC.Exts
+
+#include "MachDeps.h"
+
+-- | Take an integer base and return (pow, base^pow),
+--   where base^pow <= maxBound and pow is as large as possible.
+selectPower :: Word# -> (# Word#, Word# #)
+#if WORD_SIZE_IN_BITS == 31
+selectPower 2## = (# 31##, 2147483648## #)
+#elif WORD_SIZE_IN_BITS == 32
+selectPower 2## = (# 31##, 2147483648## #)
+#else
+selectPower 2## = (# 63##, 9223372036854775808## #)
+#endif
+
+selectPower base = go base
+  where
+    go pw = case timesWord2# pw pw of
+        (# 0##, pw2 #)
+          -> let (# n, pw2n #) = go pw2 in
+            case timesWord2# pw pw2n of
+              (# 0##, pw2n1 #) -> (#n `timesWord#` 2## `plusWord#` 1##, pw2n1 #)
+              _ -> (# n `timesWord#` 2##, pw2n #)
+        _           -> (# 1##, pw #)
+
+-- | Take an integer base and return (pow, base^pow),
+--   where base^pow <= maxBound and pow is as large as possible.
+selectPower' :: Word -> (Word, Word)
+selectPower' (W# base) = (W# power, W# poweredBase)
+  where
+    (# power, poweredBase #) = selectPower base
diff --git a/src/Data/FastDigits.hs b/src/Data/FastDigits.hs
--- a/src/Data/FastDigits.hs
+++ b/src/Data/FastDigits.hs
@@ -1,16 +1,18 @@
 {-|
 Module      : Data.FastDigits
-Description : The fast library for integer-to-digits conversion.
-Copyright   : (c) Andrew Lelechenko, 2015-2016
+Description : Integer-to-digits conversion.
+Copyright   : (c) Andrew Lelechenko, 2015-2020
 License     : GPL-3
 Maintainer  : andrew.lelechenko@gmail.com
 Stability   : experimental
 
 Convert an integer to digits and back.
-Usually this library is twice as fast as "Data.Digits".
-For small bases and long numbers it may be up to 40 times faster.
+This library is both asymptotically (O(n^1.4) vs. O(n^2))
+and practically (2x-40x for typical inputs)
+faster than "Data.Digits".
 -}
 
+{-# LANGUAGE BangPatterns  #-}
 {-# LANGUAGE MagicHash     #-}
 {-# LANGUAGE UnboxedTuples #-}
 
@@ -82,15 +84,26 @@
         else let (# fr, lr #) = digitsWordL base power r in
           fr ++ replicate (I# (unsafeCoerce# lr)) 0 ++ f q
 
+padUpTo :: Int -> [Word] -> [Word]
+padUpTo !n [] = replicate n 0
+padUpTo !n (x : xs) = x : padUpTo (n - 1) xs
+
 -- | Return digits of a non-negative number in reverse order.
 digitsUnsigned
   :: Word    -- ^ Precondition that base is ≥2 is not checked
   -> Natural
   -> [Word]
 digitsUnsigned (W# base) (NatS# n) = digitsWord base n
-digitsUnsigned (W# base) (NatJ# n) = case power of
-  1## -> digitsNatural base n
-  _   -> digitsNatural' base power poweredBase n
+digitsUnsigned (W# base) (NatJ# n)
+  | halfSize <- sizeofBigNat# n `iShiftRL#` 1#
+  , isTrue# (halfSize ># 128#)
+  = let pow = I# (word2Int# power *# halfSize) in
+    let (nHi, nLo) = NatJ# n `quotRem` (NatS# poweredBase ^ (I# halfSize)) in
+    padUpTo pow (digitsUnsigned (W# base) nLo) ++ digitsUnsigned (W# base) nHi
+  | otherwise
+  = case power of
+    1## -> digitsNatural base n
+    _   -> digitsNatural' base power poweredBase n
   where
     (# power, poweredBase #) = selectPower base
 
diff --git a/src/Data/FastDigits/Internal.hs b/src/Data/FastDigits/Internal.hs
deleted file mode 100644
--- a/src/Data/FastDigits/Internal.hs
+++ /dev/null
@@ -1,53 +0,0 @@
-{-|
-Module      : Data.FastDigits.Internal
-Copyright   : (c) Andrew Lelechenko, 2015-2016
-License     : GPL-3
-Maintainer  : andrew.lelechenko@gmail.com
-Stability   : experimental
-
--}
-
-{-# LANGUAGE CPP           #-}
-{-# LANGUAGE MagicHash     #-}
-{-# LANGUAGE UnboxedTuples #-}
-
-{-# OPTIONS_GHC -fno-warn-type-defaults  #-}
-{-# OPTIONS_GHC -O2                      #-}
-{-# OPTIONS_GHC -optc-O3                 #-}
-
-module Data.FastDigits.Internal
-  ( selectPower
-  , selectPower'
-  ) where
-
-import GHC.Exts
-
-#include "MachDeps.h"
-
--- | Take an integer base and return (pow, base^pow),
---   where base^pow <= maxBound and pow is as large as possible.
-selectPower :: Word# -> (# Word#, Word# #)
-#if WORD_SIZE_IN_BITS == 31
-selectPower 2## = (# 31##, 2147483648## #)
-#elif WORD_SIZE_IN_BITS == 32
-selectPower 2## = (# 31##, 2147483648## #)
-#else
-selectPower 2## = (# 63##, 9223372036854775808## #)
-#endif
-
-selectPower base = go base
-  where
-    go pw = case timesWord2# pw pw of
-        (# 0##, pw2 #)
-          -> let (# n, pw2n #) = go pw2 in
-            case timesWord2# pw pw2n of
-              (# 0##, pw2n1 #) -> (#n `timesWord#` 2## `plusWord#` 1##, pw2n1 #)
-              _ -> (# n `timesWord#` 2##, pw2n #)
-        _           -> (# 1##, pw #)
-
--- | Take an integer base and return (pow, base^pow),
---   where base^pow <= maxBound and pow is as large as possible.
-selectPower' :: Word -> (Word, Word)
-selectPower' (W# base) = (W# power, W# poweredBase)
-  where
-    (# power, poweredBase #) = selectPower base
