-- Copyright 2013 Evan Laforge
-- This program is distributed under the terms of the GNU General Public
-- License 3.0, see COPYING or http://www.gnu.org/licenses/gpl-3.0.txt

-- | ApproxEq class for comparing floating point numbers.
module Util.Test.ApproxEq (ApproxEq(eq), neq, compare) where
import Prelude hiding (compare)
import qualified Data.Text as Text

import qualified Util.Num as Num


compare :: (ApproxEq a, Ord a) => Double -> a -> a -> Ordering
compare :: forall a. (ApproxEq a, Ord a) => Double -> a -> a -> Ordering
compare Double
eta a
a a
b
    | Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
a a
b = Ordering
EQ
    | a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
b = Ordering
GT
    | Bool
otherwise = Ordering
LT

class ApproxEq a where
    eq :: Double -> a -> a -> Bool

neq :: ApproxEq a => Double -> a -> a -> Bool
neq :: forall a. ApproxEq a => Double -> a -> a -> Bool
neq Double
eta a
x a
y = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
x a
y

instance ApproxEq Float where
    eq :: Double -> Float -> Float -> Bool
eq Double
eta Float
x Float
y = Float -> Float
forall a. Num a => a -> a
abs (Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
y) Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Double -> Float
Num.d2f Double
eta
instance ApproxEq Double where
    eq :: Double -> Double -> Double -> Bool
eq Double
eta Double
x Double
y = Double -> Double
forall a. Num a => a -> a
abs (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
y) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
eta

-- * prelude types

instance ApproxEq Char where eq :: Double -> Char -> Char -> Bool
eq Double
_ = Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
(==)
instance ApproxEq Int where eq :: Double -> Int -> Int -> Bool
eq Double
_ = Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(==)
instance ApproxEq Integer where eq :: Double -> Integer -> Integer -> Bool
eq Double
_ = Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
(==)
instance ApproxEq Bool where eq :: Double -> Bool -> Bool -> Bool
eq Double
_ = Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance ApproxEq a => ApproxEq [a] where
    eq :: Double -> [a] -> [a] -> Bool
eq Double
eta = [a] -> [a] -> Bool
forall {a}. ApproxEq a => [a] -> [a] -> Bool
go
        where
        go :: [a] -> [a] -> Bool
go [] [] = Bool
True
        go [] [a]
_ = Bool
False
        go [a]
_ [] = Bool
False
        go (a
x:[a]
xs) (a
y:[a]
ys) = Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
x a
y Bool -> Bool -> Bool
&& [a] -> [a] -> Bool
go [a]
xs [a]
ys

instance ApproxEq a => ApproxEq (Maybe a) where
    eq :: Double -> Maybe a -> Maybe a -> Bool
eq Double
eta (Just a
x) (Just a
y) = Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
x a
y
    eq Double
_ Maybe a
_ Maybe a
_ = Bool
False

instance (ApproxEq a, ApproxEq b) => ApproxEq (Either a b) where
    eq :: Double -> Either a b -> Either a b -> Bool
eq Double
eta (Right b
x) (Right b
y) = Double -> b -> b -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta b
x b
y
    eq Double
eta (Left a
x) (Left a
y) = Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
x a
y
    eq Double
_ Either a b
_ Either a b
_ = Bool
False

instance (ApproxEq a, ApproxEq b) => ApproxEq (a, b) where
    eq :: Double -> (a, b) -> (a, b) -> Bool
eq Double
eta (a
a, b
b) (a
a', b
b') = Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
a a
a' Bool -> Bool -> Bool
&& Double -> b -> b -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta b
b b
b'
instance (ApproxEq a, ApproxEq b, ApproxEq c) => ApproxEq (a, b, c) where
    eq :: Double -> (a, b, c) -> (a, b, c) -> Bool
eq Double
eta (a
a, b
b, c
c) (a
a', b
b', c
c') = Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
a a
a' Bool -> Bool -> Bool
&& Double -> b -> b -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta b
b b
b' Bool -> Bool -> Bool
&& Double -> c -> c -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta c
c c
c'
instance (ApproxEq a, ApproxEq b, ApproxEq c, ApproxEq d) =>
        ApproxEq (a, b, c, d) where
    eq :: Double -> (a, b, c, d) -> (a, b, c, d) -> Bool
eq Double
eta (a
a, b
b, c
c, d
d) (a
a', b
b', c
c', d
d') =
        Double -> a -> a -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta a
a a
a' Bool -> Bool -> Bool
&& Double -> b -> b -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta b
b b
b' Bool -> Bool -> Bool
&& Double -> c -> c -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta c
c c
c' Bool -> Bool -> Bool
&& Double -> d -> d -> Bool
forall a. ApproxEq a => Double -> a -> a -> Bool
eq Double
eta d
d d
d'

-- * hackage types

instance ApproxEq Text.Text where eq :: Double -> Text -> Text -> Bool
eq Double
_ = Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
(==)