diff --git a/Data/Attoparsec/ByteString.hs b/Data/Attoparsec/ByteString.hs
--- a/Data/Attoparsec/ByteString.hs
+++ b/Data/Attoparsec/ByteString.hs
@@ -47,10 +47,13 @@
     , I.word8
     , I.anyWord8
     , I.notWord8
-    , I.peekWord8
     , I.satisfy
     , I.satisfyWith
     , I.skip
+
+    -- ** Lookahead
+    , I.peekWord8
+    , I.peekWord8'
 
     -- ** Byte classes
     , I.inClass
diff --git a/Data/Attoparsec/ByteString/Char8.hs b/Data/Attoparsec/ByteString/Char8.hs
--- a/Data/Attoparsec/ByteString/Char8.hs
+++ b/Data/Attoparsec/ByteString/Char8.hs
@@ -46,9 +46,12 @@
     , char8
     , anyChar
     , notChar
-    , peekChar
     , satisfy
 
+    -- ** Lookahead
+    , peekChar
+    , peekChar'
+
     -- ** Special character parsers
     , digit
     , letter_iso8859_15
@@ -106,7 +109,7 @@
     , I.atEnd
     ) where
 
-import Control.Applicative ((*>), (<*), (<$>), (<|>))
+import Control.Applicative (pure, (*>), (<*), (<$>), (<|>))
 import Data.Attoparsec.ByteString.FastSet (charClass, memberChar)
 import Data.Attoparsec.ByteString.Internal (Parser, (<?>))
 import Data.Attoparsec.Combinator
@@ -114,8 +117,8 @@
 import Data.Bits (Bits, (.|.), shiftL)
 import Data.ByteString.Internal (c2w, w2c)
 import Data.Int (Int8, Int16, Int32, Int64)
-import Data.Ratio ((%))
 import Data.String (IsString(..))
+import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
 import Data.Word (Word8, Word16, Word32, Word64, Word)
 import Prelude hiding (takeWhile)
 import qualified Data.Attoparsec.ByteString as A
@@ -223,8 +226,8 @@
 anyChar = satisfy $ const True
 {-# INLINE anyChar #-}
 
--- | Match any character. Returns 'Nothing' if end of input has been
--- reached. Does not consume any input.
+-- | Match any character, to perform lookahead. Returns 'Nothing' if
+-- end of input has been reached. Does not consume any input.
 --
 -- /Note/: Because this parser does not fail, do not use it with
 -- combinators such as 'many', because such parsers loop until a
@@ -233,6 +236,12 @@
 peekChar = (fmap w2c) `fmap` I.peekWord8
 {-# INLINE peekChar #-}
 
+-- | Match any character, to perform lookahead.  Does not consume any
+-- input, but will fail if end of input has been reached.
+peekChar' :: Parser Char
+peekChar' = w2c `fmap` I.peekWord8'
+{-# INLINE peekChar' #-}
+
 -- | Fast predicate for matching ASCII space characters.
 --
 -- /Note/: This predicate only gives correct answers for the ASCII
@@ -471,8 +480,8 @@
 {-# SPECIALIZE rational :: Parser Double #-}
 {-# SPECIALIZE rational :: Parser Float #-}
 {-# SPECIALIZE rational :: Parser Rational #-}
-rational = floaty $ \real frac fracDenom -> fromRational $
-                     real % 1 + frac % fracDenom
+{-# SPECIALIZE rational :: Parser Scientific #-}
+rational = scientifically realToFrac
 
 -- | Parse a rational number.
 --
@@ -490,12 +499,7 @@
 -- This function does not accept string representations of \"NaN\" or
 -- \"Infinity\".
 double :: Parser Double
-double = floaty asDouble
-
-asDouble :: Integer -> Integer -> Integer -> Double
-asDouble real frac fracDenom =
-    fromIntegral real + fromIntegral frac / fromIntegral fracDenom
-{-# INLINE asDouble #-}
+double = rational
 
 -- | Parse a number, attempting to preserve both speed and precision.
 --
@@ -507,43 +511,38 @@
 -- 'rational'.
 --
 -- This function does not accept string representations of \"NaN\" or
--- \"Infinity\".
+-- \"
 number :: Parser Number
-number = floaty $ \real frac fracDenom ->
-         if frac == 0 && fracDenom == 0
-         then I real
-         else D (asDouble real frac fracDenom)
-{-# INLINE number #-}
-
-data T = T !Integer !Int
+number = scientifically $ \s ->
+            let e = base10Exponent s
+                c = coefficient s
+            in if e >= 0
+               then I (c * 10 ^ e)
+               else D (fromInteger c / 10 ^ negate e)
 
-floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
-{-# INLINE floaty #-}
-floaty f = do
+{-# INLINE scientifically #-}
+scientifically :: (Scientific -> a) -> Parser a
+scientifically h = do
   let minus = 45
       plus  = 43
   !positive <- ((== plus) <$> I.satisfy (\c -> c == minus || c == plus)) <|>
-               return True
-  real <- decimal
-  let tryFraction = do
-        let dot = 46
-        _ <- I.satisfy (==dot)
-        ds <- I.takeWhile isDigit_w8
-        case I.parseOnly decimal ds of
-                Right n -> return $ T n (B.length ds)
-                _       -> fail "no digits after decimal"
-  T fraction fracDigits <- tryFraction <|> return (T 0 0)
+               pure True
+
+  n <- decimal
+
+  let f fracDigits = scientific (B8.foldl' step n fracDigits)
+                                (negate $ B8.length fracDigits)
+      step a w = a * 10 + fromIntegral (w - 48)
+
+  s <- let dot = 46 in
+       (I.satisfy (==dot) *> (f <$> I.takeWhile isDigit_w8)) <|>
+         pure (scientific n 0)
+
+  let !signedCoeff | positive  =          coefficient s
+                   | otherwise = negate $ coefficient s
+
   let littleE = 101
       bigE    = 69
-      e w = w == littleE || w == bigE
-  power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
-  let n = if fracDigits == 0
-          then if power == 0
-               then fromIntegral real
-               else fromIntegral real * (10 ^^ power)
-          else if power == 0
-               then f real fraction (10 ^ fracDigits)
-               else f real fraction (10 ^ fracDigits) * (10 ^^ power)
-  return $ if positive
-           then n
-           else -n
+  (I.satisfy (\c -> c == littleE || c == bigE) *>
+      fmap (h . scientific signedCoeff . (base10Exponent s +)) (signed decimal)) <|>
+    return (h $ scientific signedCoeff   (base10Exponent s))
diff --git a/Data/Attoparsec/ByteString/FastSet.hs b/Data/Attoparsec/ByteString/FastSet.hs
--- a/Data/Attoparsec/ByteString/FastSet.hs
+++ b/Data/Attoparsec/ByteString/FastSet.hs
@@ -83,7 +83,7 @@
     where search lo hi
               | hi < lo = False
               | otherwise =
-                  let mid = (lo + hi) `div` 2
+                  let mid = (lo + hi) `quot` 2
                   in case compare w (U.unsafeIndex s mid) of
                        GT -> search (mid + 1) hi
                        LT -> search lo (mid - 1)
diff --git a/Data/Attoparsec/ByteString/Internal.hs b/Data/Attoparsec/ByteString/Internal.hs
--- a/Data/Attoparsec/ByteString/Internal.hs
+++ b/Data/Attoparsec/ByteString/Internal.hs
@@ -34,7 +34,10 @@
     , skip
     , word8
     , notWord8
+
+    -- ** Lookahead
     , peekWord8
+    , peekWord8'
 
     -- ** Byte classes
     , inClass
@@ -426,8 +429,8 @@
 notWord8 c = satisfy (/= c) <?> "not " ++ show c
 {-# INLINE notWord8 #-}
 
--- | Match any byte. Returns 'Nothing' if end of input has been
--- reached. Does not consume any input.
+-- | Match any byte, to perform lookahead. Returns 'Nothing' if end of
+-- input has been reached. Does not consume any input.
 --
 -- /Note/: Because this parser does not fail, do not use it with
 -- combinators such as 'many', because such parsers loop until a
@@ -444,6 +447,14 @@
             else let !w = B.unsafeHead (unI i0)
                  in ks i0 a0 m0 (Just w)
 {-# INLINE peekWord8 #-}
+
+-- | Match any byte, to perform lookahead.  Does not consume any
+-- input, but will fail if end of input has been reached.
+peekWord8' :: Parser Word8
+peekWord8' = do
+  s <- ensure 1
+  return $! B.unsafeHead s
+{-# INLINE peekWord8' #-}
 
 -- | Match only if all input has been consumed.
 endOfInput :: Parser ()
diff --git a/Data/Attoparsec/ByteString/Lazy.hs b/Data/Attoparsec/ByteString/Lazy.hs
--- a/Data/Attoparsec/ByteString/Lazy.hs
+++ b/Data/Attoparsec/ByteString/Lazy.hs
@@ -7,8 +7,8 @@
 -- Stability   :  experimental
 -- Portability :  unknown
 --
--- Simple, efficient combinator parsing for lazy 'ByteString'
--- strings, loosely based on the Parsec library.
+-- Simple, efficient combinator parsing that can consume lazy
+-- 'ByteString' strings, loosely based on the Parsec library.
 --
 -- This is essentially the same code as in the 'Data.Attoparsec'
 -- module, only with a 'parse' function that can consume a lazy
@@ -16,10 +16,11 @@
 -- more input to be fed in.  Think of this as suitable for use with a
 -- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.
 --
--- Behind the scenes, strict 'B.ByteString' values are still used
--- internally to store parser input and manipulate it efficiently.
--- High-performance parsers such as 'string' still expect strict
--- 'B.ByteString' parameters.
+-- /Note:/ The various parser functions and combinators such as
+-- 'string' still expect /strict/ 'B.ByteString' parameters, and
+-- return strict 'B.ByteString' results.  Behind the scenes, strict
+-- 'B.ByteString' values are still used internally to store parser
+-- input and manipulate it efficiently.
 
 module Data.Attoparsec.ByteString.Lazy
     (
diff --git a/Data/Attoparsec/Number.hs b/Data/Attoparsec/Number.hs
--- a/Data/Attoparsec/Number.hs
+++ b/Data/Attoparsec/Number.hs
@@ -10,10 +10,7 @@
 --
 -- A simple number type, useful for parsing both exact and inexact
 -- quantities without losing much precision.
-module Data.Attoparsec.Number
-    (
-      Number(..)
-    ) where
+module Data.Attoparsec.Number ( Number(..) ) where
 
 import Control.DeepSeq (NFData(rnf))
 import Data.Data (Data)
diff --git a/Data/Attoparsec/Text.hs b/Data/Attoparsec/Text.hs
--- a/Data/Attoparsec/Text.hs
+++ b/Data/Attoparsec/Text.hs
@@ -52,7 +52,10 @@
     , I.satisfy
     , I.satisfyWith
     , I.skip
+
+    -- ** Lookahead
     , I.peekChar
+    , I.peekChar'
 
     -- ** Special character parsers
     , digit
@@ -103,14 +106,14 @@
     , I.atEnd
     ) where
 
-import Control.Applicative ((<$>), (*>), (<*), (<|>))
+import Control.Applicative (pure, (<$>), (*>), (<*), (<|>))
 import Data.Attoparsec.Combinator
 import Data.Attoparsec.Number (Number(..))
+import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
 import Data.Attoparsec.Text.Internal ((<?>), Parser, Result, parse, takeWhile1)
 import Data.Bits (Bits, (.|.), shiftL)
 import Data.Char (isAlpha, isDigit, isSpace, ord)
 import Data.Int (Int8, Int16, Int32, Int64)
-import Data.Ratio ((%))
 import Data.Text (Text)
 import Data.Word (Word8, Word16, Word32, Word64, Word)
 import qualified Data.Attoparsec.Internal as I
@@ -343,8 +346,8 @@
 {-# SPECIALIZE rational :: Parser Double #-}
 {-# SPECIALIZE rational :: Parser Float #-}
 {-# SPECIALIZE rational :: Parser Rational #-}
-rational = floaty $ \real frac fracDenom -> fromRational $
-                     real % 1 + frac % fracDenom
+{-# SPECIALIZE rational :: Parser Scientific #-}
+rational = scientifically realToFrac
 
 -- | Parse a rational number.
 --
@@ -362,12 +365,7 @@
 -- This function does not accept string representations of \"NaN\" or
 -- \"Infinity\".
 double :: Parser Double
-double = floaty asDouble
-
-asDouble :: Integer -> Integer -> Integer -> Double
-asDouble real frac fracDenom =
-    fromIntegral real + fromIntegral frac / fromIntegral fracDenom
-{-# INLINE asDouble #-}
+double = rational
 
 -- | Parse a number, attempting to preserve both speed and precision.
 --
@@ -381,12 +379,35 @@
 -- This function does not accept string representations of \"NaN\" or
 -- \"Infinity\".
 number :: Parser Number
-number = floaty $ \real frac fracDenom ->
-         if frac == 0 && fracDenom == 0
-         then I real
-         else D (asDouble real frac fracDenom)
-{-# INLINE number #-}
+number = scientifically $ \s ->
+            let e = base10Exponent s
+                c = coefficient s
+            in if e >= 0
+               then I (c * 10 ^ e)
+               else D (fromInteger c / 10 ^ negate e)
 
+{-# INLINE scientifically #-}
+scientifically :: (Scientific -> a) -> Parser a
+scientifically h = do
+  !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
+               pure True
+
+  n <- decimal
+
+  let f fracDigits = scientific (T.foldl' step n fracDigits)
+                                (negate $ T.length fracDigits)
+      step a c = a * 10 + fromIntegral (ord c - 48)
+
+  s <- (I.satisfy (=='.') *> (f <$> I.takeWhile isDigit)) <|>
+         pure (scientific n 0)
+
+  let !signedCoeff | positive  =          coefficient s
+                   | otherwise = negate $ coefficient s
+
+  (I.satisfy (\c -> c == 'e' || c == 'E') *>
+      fmap (h . scientific signedCoeff . (base10Exponent s +)) (signed decimal)) <|>
+    return (h $ scientific signedCoeff   (base10Exponent s))
+
 -- | Parse a single digit, as recognised by 'isDigit'.
 digit :: Parser Char
 digit = I.satisfy isDigit <?> "digit"
@@ -433,31 +454,3 @@
 -- | Type-specialized version of '<*' for 'Text'.
 (<*.) :: Parser a -> Text -> Parser a
 f <*. s = f <* I.string s
-
-data T = T !Integer !Int
-
-floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
-{-# INLINE floaty #-}
-floaty f = do
-  !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
-               return True
-  real <- decimal
-  let tryFraction = do
-        _ <- I.satisfy (=='.')
-        ds <- I.takeWhile isDigit
-        case I.parseOnly decimal ds of
-                Right n -> return $ T n (T.length ds)
-                _       -> fail "no digits after decimal"
-  T fraction fracDigits <- tryFraction <|> return (T 0 0)
-  let e c = c == 'e' || c == 'E'
-  power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
-  let n = if fracDigits == 0
-          then if power == 0
-               then fromIntegral real
-               else fromIntegral real * (10 ^^ power)
-          else if power == 0
-               then f real fraction (10 ^ fracDigits)
-               else f real fraction (10 ^ fracDigits) * (10 ^^ power)
-  return $ if positive
-           then n
-           else -n
diff --git a/Data/Attoparsec/Text/FastSet.hs b/Data/Attoparsec/Text/FastSet.hs
--- a/Data/Attoparsec/Text/FastSet.hs
+++ b/Data/Attoparsec/Text/FastSet.hs
@@ -50,7 +50,7 @@
     where search lo hi
               | hi < lo = False
               | otherwise =
-                  let mid = (lo + hi) `div` 2
+                  let mid = (lo + hi) `quot` 2
                   in case compare c (AB.unsafeAt a mid) of
                        GT -> search (mid + 1) hi
                        LT -> search lo (mid - 1)
diff --git a/Data/Attoparsec/Text/Internal.hs b/Data/Attoparsec/Text/Internal.hs
--- a/Data/Attoparsec/Text/Internal.hs
+++ b/Data/Attoparsec/Text/Internal.hs
@@ -35,7 +35,10 @@
     , skip
     , char
     , notChar
+
+    -- ** Lookahead
     , peekChar
+    , peekChar'
 
     -- ** Character classes
     , inClass
@@ -90,7 +93,7 @@
     fromString = string . T.pack
 
 lengthAtLeast :: T.Text -> Int -> Bool
-lengthAtLeast t@(T.Text _ _ len) n = (len `div` 2) >= n || T.length t >= n
+lengthAtLeast t@(T.Text _ _ len) n = (len `quot` 2) >= n || T.length t >= n
 {-# INLINE lengthAtLeast #-}
 
 -- | If at least @n@ characters of input are available, return the
@@ -440,8 +443,8 @@
 notChar c = satisfy (/= c) <?> "not " ++ show c
 {-# INLINE notChar #-}
 
--- | Match any character. Returns 'Nothing' if end of input has been
--- reached. Does not consume any input.
+-- | Match any character, to perform lookahead. Returns 'Nothing' if
+-- end of input has been reached. Does not consume any input.
 --
 -- /Note/: Because this parser does not fail, do not use it with
 -- combinators such as 'many', because such parsers loop until a
@@ -458,6 +461,14 @@
            else let !c = unsafeHead (unI i0)
                 in ks i0 a0 m0 (Just c)
 {-# INLINE peekChar #-}
+
+-- | Match any character, to perform lookahead.  Does not consume any
+-- input, but will fail if end of input has been reached.
+peekChar' :: Parser Char
+peekChar' = do
+  s <- ensure 1
+  return $! unsafeHead s
+{-# INLINE peekChar' #-}
 
 -- | Match only if all input has been consumed.
 endOfInput :: Parser ()
diff --git a/Data/Attoparsec/Text/Lazy.hs b/Data/Attoparsec/Text/Lazy.hs
--- a/Data/Attoparsec/Text/Lazy.hs
+++ b/Data/Attoparsec/Text/Lazy.hs
@@ -7,7 +7,7 @@
 -- Stability   :  experimental
 -- Portability :  unknown
 --
--- Simple, efficient combinator parsing for lazy 'Text'
+-- Simple, efficient combinator parsing that can consume lazy 'Text'
 -- strings, loosely based on the Parsec library.
 --
 -- This is essentially the same code as in the 'Data.Attoparsec.Text'
@@ -16,10 +16,11 @@
 -- more input to be fed in.  Think of this as suitable for use with a
 -- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.
 --
--- Behind the scenes, strict 'T.Text' values are still used
--- internally to store parser input and manipulate it efficiently.
--- High-performance parsers such as 'string' still expect strict
--- 'T.Text' parameters.
+-- /Note:/ The various parser functions and combinators such as
+-- 'string' still expect /strict/ 'T.Text' parameters, and return
+-- strict 'T.Text' results.  Behind the scenes, strict 'T.Text' values
+-- are still used internally to store parser input and manipulate it
+-- efficiently.
 
 module Data.Attoparsec.Text.Lazy
     (
diff --git a/attoparsec.cabal b/attoparsec.cabal
--- a/attoparsec.cabal
+++ b/attoparsec.cabal
@@ -1,12 +1,12 @@
 name:            attoparsec
-version:         0.10.4.0
+version:         0.11.1.0
 license:         BSD3
 license-file:    LICENSE
 category:        Text, Parsing
 author:          Bryan O'Sullivan <bos@serpentine.com>
 maintainer:      Bryan O'Sullivan <bos@serpentine.com>
 stability:       experimental
-tested-with:     GHC == 6.12.3, GHC == 7.0.3, GHC == 7.2.1, GHC == 7.4.2, GHC == 7.6.1
+tested-with:     GHC == 7.0, GHC == 7.2, GHC == 7.4, GHC == 7.6, GHC == 7.8
 synopsis:        Fast combinator parsing for bytestrings and text
 cabal-version:   >= 1.8
 homepage:        https://github.com/bos/attoparsec
@@ -23,6 +23,7 @@
     benchmarks/Tiny.hs
     benchmarks/attoparsec-benchmarks.cabal
     benchmarks/med.txt.bz2
+    changelog
     examples/Makefile
     examples/Parsec_RFC2616.hs
     examples/RFC2616.hs
@@ -43,7 +44,8 @@
                  bytestring,
                  containers,
                  deepseq,
-                 text >= 0.11.1.5
+                 text >= 0.11.1.5,
+                 scientific >= 0.2
 
   exposed-modules: Data.Attoparsec
                    Data.Attoparsec.ByteString
diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs
--- a/benchmarks/Benchmarks.hs
+++ b/benchmarks/Benchmarks.hs
@@ -6,6 +6,7 @@
 import Data.Bits (unsafeShiftL)
 import Data.ByteString.Internal (ByteString(..))
 import Data.Char
+import Data.Scientific (Scientific(..))
 import Data.Word (Word32)
 import Text.Parsec.Text ()
 import Text.Parsec.Text.Lazy ()
@@ -80,6 +81,60 @@
    , bgroup "scan" [
        bench "short" $ nf (AB.parse quotedString) (BC.pack "abcdefghijk\"")
      , bench "long" $ nf (AB.parse quotedString) b
+     ]
+
+   , let strN     = "1234.56789"
+         strNePos = "1234.56789e3"
+         strNeNeg = "1234.56789e-3"
+     in
+     bgroup "numbers"
+     [ let !tN     = T.pack strN
+           !tNePos = T.pack strNePos
+           !tNeNeg = T.pack strNeNeg
+       in bgroup "Text"
+       [
+         bgroup "no power"
+         [ bench "double"     $ nf (AT.parseOnly AT.double)                            tN
+         , bench "number"     $ nf (AT.parseOnly AT.number)                            tN
+         , bench "rational"   $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational))  tN
+         , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tN
+         ]
+       , bgroup "positive power"
+         [ bench "double"     $ nf (AT.parseOnly AT.double)                            tNePos
+         , bench "number"     $ nf (AT.parseOnly AT.number)                            tNePos
+         , bench "rational"   $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational))  tNePos
+         , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tNePos
+         ]
+       , bgroup "negative power"
+         [ bench "double"     $ nf (AT.parseOnly AT.double)                            tNeNeg
+         , bench "number"     $ nf (AT.parseOnly AT.number)                            tNeNeg
+         , bench "rational"   $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational))  tNeNeg
+         , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tNeNeg
+         ]
+       ]
+     , let !bN     = BC.pack strN
+           !bNePos = BC.pack strNePos
+           !bNeNeg = BC.pack strNeNeg
+       in bgroup "ByteString"
+       [ bgroup "no power"
+         [ bench "double"     $ nf (AC.parseOnly AC.double)                             bN
+         , bench "number"     $ nf (AC.parseOnly AC.number)                             bN
+         , bench "rational"   $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational))   bN
+         , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bN
+         ]
+       , bgroup "positive power"
+         [ bench "double"     $ nf (AC.parseOnly AC.double)                             bNePos
+         , bench "number"     $ nf (AC.parseOnly AC.number)                             bNePos
+         , bench "rational"   $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational))   bNePos
+         , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bNePos
+         ]
+       , bgroup "negative power"
+         [ bench "double"     $ nf (AC.parseOnly AC.double)                             bNeNeg
+         , bench "number"     $ nf (AC.parseOnly AC.number)                             bNeNeg
+         , bench "rational"   $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational))   bNeNeg
+         , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bNeNeg
+         ]
+       ]
      ]
    ]
 
diff --git a/benchmarks/attoparsec-benchmarks.cabal b/benchmarks/attoparsec-benchmarks.cabal
--- a/benchmarks/attoparsec-benchmarks.cabal
+++ b/benchmarks/attoparsec-benchmarks.cabal
@@ -3,16 +3,19 @@
 
 name: attoparsec-benchmarks
 version: 0
-cabal-version: >=1.2
+cabal-version: >=1.6
 build-type: Simple
 
 executable attoparsec-benchmarks
   main-is: Benchmarks.hs
+  hs-source-dirs: .. .
+  ghc-options: -O2
   build-depends:
-    attoparsec,
-    base,
+    array,
+    base == 4.*,
     bytestring,
     criterion >= 0.5,
-    deepseq == 1.1.*,
+    deepseq >= 1.1,
     parsec >= 3.1.2,
+    scientific,
     text
diff --git a/changelog b/changelog
new file mode 100644
--- /dev/null
+++ b/changelog
@@ -0,0 +1,7 @@
+0.11.1.0
+
+	* New dependency: the scientific package.  This allows us to parse
+	  numbers much more efficiently.
+
+	* peekWord8', peekChar': new primitive parsers that allow
+	  single-character lookahead.
