diff --git a/QuickCheck.cabal b/QuickCheck.cabal
--- a/QuickCheck.cabal
+++ b/QuickCheck.cabal
@@ -1,5 +1,5 @@
 Name: QuickCheck
-Version: 2.12.2
+Version: 2.12.3
 Cabal-Version: >= 1.8
 Build-type: Simple
 License: BSD3
@@ -55,7 +55,7 @@
 source-repository this
   type:     git
   location: https://github.com/nick8325/quickcheck
-  tag:      2.12.2
+  tag:      2.12.3
 
 flag templateHaskell
   Description: Build Test.QuickCheck.All, which uses Template Haskell.
diff --git a/Test/QuickCheck.hs b/Test/QuickCheck.hs
--- a/Test/QuickCheck.hs
+++ b/Test/QuickCheck.hs
@@ -80,6 +80,7 @@
   , shrinkMapBy
   , shrinkIntegral
   , shrinkRealFrac
+  , shrinkDecimal
 
     -- ** Lifting of 'Arbitrary' to unary and binary type constructors
   , Arbitrary1(..)
diff --git a/Test/QuickCheck/Arbitrary.hs b/Test/QuickCheck/Arbitrary.hs
--- a/Test/QuickCheck/Arbitrary.hs
+++ b/Test/QuickCheck/Arbitrary.hs
@@ -66,6 +66,7 @@
   , shrinkMapBy              -- :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b]
   , shrinkIntegral           -- :: Integral a => a -> [a]
   , shrinkRealFrac           -- :: RealFrac a => a -> [a]
+  , shrinkDecimal            -- :: RealFrac a => a -> [a]
   -- ** Helper functions for implementing coarbitrary
   , coarbitraryIntegral      -- :: Integral a => a -> Gen b -> Gen b
   , coarbitraryReal          -- :: Real a => a -> Gen b -> Gen b
@@ -492,7 +493,7 @@
 #ifndef NO_FIXED
 instance HasResolution a => Arbitrary (Fixed a) where
   arbitrary = arbitrarySizedFractional
-  shrink    = shrinkRealFrac
+  shrink    = shrinkDecimal
 #endif
 
 instance Arbitrary2 (,) where
@@ -676,11 +677,11 @@
 
 instance Arbitrary Float where
   arbitrary = arbitrarySizedFractional
-  shrink    = shrinkRealFrac
+  shrink    = shrinkDecimal
 
 instance Arbitrary Double where
   arbitrary = arbitrarySizedFractional
-  shrink    = shrinkRealFrac
+  shrink    = shrinkDecimal
 
 instance Arbitrary CChar where
   arbitrary = arbitrarySizedBoundedIntegral
@@ -782,11 +783,11 @@
 
 instance Arbitrary CFloat where
   arbitrary = arbitrarySizedFractional
-  shrink = shrinkRealFrac
+  shrink = shrinkDecimal
 
 instance Arbitrary CDouble where
   arbitrary = arbitrarySizedFractional
-  shrink = shrinkRealFrac
+  shrink = shrinkDecimal
 
 -- Arbitrary instances for container types
 instance (Ord a, Arbitrary a) => Arbitrary (Set.Set a) where
@@ -1096,29 +1097,46 @@
             (True,  False) -> a + b < 0
             (False, True)  -> a + b > 0
 
--- | Shrink a fraction, via continued-fraction approximations.
+-- | Shrink a fraction, preferring numbers with smaller
+-- numerators or denominators. See also 'shrinkDecimal'.
 shrinkRealFrac :: RealFrac a => a -> [a]
-shrinkRealFrac a = shrinkRealFracToPrecision (abs a*1e-6) a
+shrinkRealFrac x
+  | not (x == x)  = 0 : take 10 (iterate (*2) 0) -- NaN
+  | not (2*x+1>x) = 0 : takeWhile (<x) (iterate (*2) 0) -- infinity
+  | x < 0 = negate x:map negate (shrinkRealFrac (negate x))
+  | otherwise =
+    -- To ensure termination
+    filter (\y -> abs y < abs x) $
+      -- Try shrinking to an integer first
+      map fromInteger (shrink (truncate x) ++ [truncate x]) ++
+      -- Shrink the numerator
+      [fromRational (num' % denom) | num' <- shrink num] ++
+      -- Shrink the denominator, and keep the fraction as close
+      -- to the original as possible, rounding towards zero
+      [fromRational (truncate (num * denom' % denom) % denom')
+      | denom' <- shrink denom, denom' /= 0 ]
+  where
+    num = numerator (toRational x)
+    denom = denominator (toRational x)
 
-shrinkRealFracToPrecision :: RealFrac a
-                   => a   -- ^ "Epsilon" – the minimum deviation we consider
-                   -> a   -- ^ Value to shrink
-                   -> [a]
-shrinkRealFracToPrecision eps x
-  | x < 0       = 0 : ([id, negate] <*> filter (>0) (shrinkRealFracToPrecision eps $ -x))
-  | x < eps     = [0 | x /= 0]
-  | not (x==x)  = []
-  | not (2*x>x) = 0 : takeWhile (<x) ((2^).(^2)<$>[0..])
-  | (x-intgPart>eps)
-                = filter (/= x) $
-                  intgShrinks ++ [intgPart]
-                   ++ map ((intgPart+) . recip)
-                          (filter (>0)
-                            . shrinkRealFracToPrecision (eps/(x-intgPart))
-                                  $ 1/(x-intgPart))
-  | otherwise   = intgShrinks
- where intgPart = fromInteger $ truncate x
-       intgShrinks = map fromInteger . shrinkIntegral $ truncate x
+-- | Shrink a real number, preferring numbers with shorter
+-- decimal representations. See also 'shrinkRealFrac'.
+shrinkDecimal :: RealFrac a => a -> [a]
+shrinkDecimal x
+  | not (x == x)  = 0 : take 10 (iterate (*2) 0)        -- NaN
+  | not (2*x+1>x) = 0 : takeWhile (<x) (iterate (*2) 0) -- infinity
+  | otherwise =
+    -- e.g. shrink pi =
+    --   shrink 3 ++ map (/ 10) (shrink 31) ++
+    --   map (/ 100) (shrink 314) + ...,
+    -- where the inner calls to shrink use integer shrinking.
+    [ y
+    | precision <- take 6 (iterate (*10) 1),
+      let m = truncate (toRational x * precision),
+      m `mod` 10 /= 0, -- don't allow shrinking to increase digits
+      n <- m:shrink m,
+      let y = fromRational (fromInteger n / precision),
+      abs y < abs x ]
 
 --------------------------------------------------------------------------
 -- ** CoArbitrary
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,4 +1,12 @@
-QuickCheck 2.12.2 (released 2018-09-06)
+QuickCheck 2.12.3 (released 2018-09-12)
+	* Shrinking for Float and Decimal now works by reducing the number
+	  of digits in the number. The new function shrinkDecimal
+	  implements this shrinking behaviour.
+	* Shrinking for Rational now tries to make the numerator and
+	  denominator of the number smaller. Previously it tried to reduce
+	  the magnitude of the number.
+
+QuickCheck 2.12.2 (released 2018-09-10)
 	* Fix infinite shrinking loop for fractional types.
 	* Add SortedList modifier.
 
@@ -22,7 +30,7 @@
 		  case distribution more flexibly than label.
 		- When label is called multiple times in a property, each call
 		  produces a separate table of frequencies.
-	
+
 	* New functions:
 		- (=/=): like (/=), but prints a counterexample
 		  (thanks to tom-bop)
@@ -50,7 +58,7 @@
 		  argument is not evaluated and the whole disjunction is
 		  considered to have a false precondition
 		- Bug fix: suchThatMaybe always increased size to at least 1
-	
+
 	* Miscellaneous API changes:
 		- Result type has changed a bit:
 			- InsufficientCovered constructor is gone
diff --git a/tests/Generators.hs b/tests/Generators.hs
--- a/tests/Generators.hs
+++ b/tests/Generators.hs
@@ -14,14 +14,14 @@
 instance Arbitrary a => Arbitrary (Path a) where
   arbitrary = do
     x <- arbitrary
-    fmap Path (pathFrom x)
+    fmap Path (pathFrom 100 x)
     where
-      pathFrom x = sized $ \n ->
+      pathFrom n x =
         fmap (x:) $
         case shrink x of
           [] -> return []
           _ | n == 0 -> return []
-          ys -> oneof [resize (n-1) (pathFrom y) | y <- ys]
+          ys -> oneof [pathFrom (n-1) y | y <- ys]
 
   shrink (Path xs) = map Path [ ys | ys <- inits xs, length ys > 0 && length ys < length xs ]
 
