diff options
Diffstat (limited to 'libraries/base/Data/Ratio.hs')
-rw-r--r-- | libraries/base/Data/Ratio.hs | 49 |
1 files changed, 27 insertions, 22 deletions
diff --git a/libraries/base/Data/Ratio.hs b/libraries/base/Data/Ratio.hs index 8517e485ff..946824fec2 100644 --- a/libraries/base/Data/Ratio.hs +++ b/libraries/base/Data/Ratio.hs @@ -47,27 +47,32 @@ import GHC.Real -- The basic defns for Ratio -- and abs r' < d', and the simplest rational is q%1 + the reciprocal of -- the simplest rational between d'%r' and d%r. -approxRational :: (RealFrac a) => a -> a -> Rational -approxRational rat eps = simplest (rat-eps) (rat+eps) - where simplest x y | y < x = simplest y x - | x == y = xr - | x > 0 = simplest' n d n' d' - | y < 0 = - simplest' (-n') d' (-n) d - | otherwise = 0 :% 1 - where xr = toRational x - n = numerator xr - d = denominator xr - nd' = toRational y - n' = numerator nd' - d' = denominator nd' +approxRational :: (RealFrac a) => a -> a -> Rational +approxRational rat eps = + -- We convert rat and eps to rational *before* subtracting/adding since + -- otherwise we may overflow. This was the cause of #14425. + simplest (toRational rat - toRational eps) (toRational rat + toRational eps) + where + simplest x y + | y < x = simplest y x + | x == y = xr + | x > 0 = simplest' n d n' d' + | y < 0 = - simplest' (-n') d' (-n) d + | otherwise = 0 :% 1 + where xr = toRational x + n = numerator xr + d = denominator xr + nd' = toRational y + n' = numerator nd' + d' = denominator nd' - simplest' n d n' d' -- assumes 0 < n%d < n'%d' - | r == 0 = q :% 1 - | q /= q' = (q+1) :% 1 - | otherwise = (q*n''+d'') :% n'' - where (q,r) = quotRem n d - (q',r') = quotRem n' d' - nd'' = simplest' d' r' d r - n'' = numerator nd'' - d'' = denominator nd'' + simplest' n d n' d' -- assumes 0 < n%d < n'%d' + | r == 0 = q :% 1 + | q /= q' = (q+1) :% 1 + | otherwise = (q*n''+d'') :% n'' + where (q,r) = quotRem n d + (q',r') = quotRem n' d' + nd'' = simplest' d' r' d r + n'' = numerator nd'' + d'' = denominator nd'' |