module MagicHaskeller.NearEq where
import MagicHaskeller.FastRatio

infix 4 ~=   -- same as (==)

-- the nearly-equal operator with pattern-matching-like behavior over NaN and Infinity.
class NearEq a where
  (~=) :: a -> a -> Bool

-- Without check with isInfinite, Infinity ~= something would always be True. Without check with signum, Infinity ~= -Infinity would always be True.
instance NearEq Double where
         Double
a ~= :: Double -> Double -> Bool
~= Double
b = Bool
naBool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
==Bool
nb Bool -> Bool -> Bool
&& Bool
ia Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
b Bool -> Bool -> Bool
&& Double -> Double
forall a. Num a => a -> a
signum Double
a Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double -> Double
forall a. Num a => a -> a
signum Double
b Bool -> Bool -> Bool
&& (Bool
na Bool -> Bool -> Bool
|| Bool
ia Bool -> Bool -> Bool
|| Double -> Double
forall a. Num a => a -> a
abs (Double
aDouble -> Double -> Double
forall a. Num a => a -> a -> a
-Double
b) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= (Int -> Double -> Double
forall a. RealFloat a => Int -> a -> a
scaleFloat (-Int
24) (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ Double -> Double
forall a. Num a => a -> a
abs Double
a))
              where na :: Bool
na = Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
a
                    nb :: Bool
nb = Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
b
                    ia :: Bool
ia = Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
a
instance NearEq Float where
         Float
a ~= :: Float -> Float -> Bool
~= Float
b = Bool
naBool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
==Bool
nb Bool -> Bool -> Bool
&& Bool
ia Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Float -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Float
b Bool -> Bool -> Bool
&& Float -> Float
forall a. Num a => a -> a
signum Float
a Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
== Float -> Float
forall a. Num a => a -> a
signum Float
b Bool -> Bool -> Bool
&& (Bool
na Bool -> Bool -> Bool
|| Bool
ia Bool -> Bool -> Bool
|| Float -> Float
forall a. Num a => a -> a
abs (Float
aFloat -> Float -> Float
forall a. Num a => a -> a -> a
-Float
b) Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= (Int -> Float -> Float
forall a. RealFloat a => Int -> a -> a
scaleFloat (-Int
12) (Float -> Float) -> Float -> Float
forall a b. (a -> b) -> a -> b
$ Float -> Float
forall a. Num a => a -> a
abs Float
a))
              where na :: Bool
na = Float -> Bool
forall a. RealFloat a => a -> Bool
isNaN Float
a
                    nb :: Bool
nb = Float -> Bool
forall a. RealFloat a => a -> Bool
isNaN Float
b
                    ia :: Bool
ia = Float -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Float
a
instance NearEq () where
  ()
x ~= :: () -> () -> Bool
~= ()
y = ()
x () -> () -> Bool
forall a. Eq a => a -> a -> Bool
== ()
y
instance NearEq Bool where
  Bool
x ~= :: Bool -> Bool -> Bool
~= Bool
y = Bool
x Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
y
instance NearEq Ordering where
  Ordering
x ~= :: Ordering -> Ordering -> Bool
~= Ordering
y = Ordering
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
y
instance NearEq Char where
  Char
x ~= :: Char -> Char -> Bool
~= Char
y = Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
y
instance NearEq Int where
  Int
x ~= :: Int -> Int -> Bool
~= Int
y = Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
y
instance NearEq Integer where
  Integer
x ~= :: Integer -> Integer -> Bool
~= Integer
y = Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
y
instance (NearEq i, Integral i) => NearEq (Ratio i) where
  Ratio i
x ~= :: Ratio i -> Ratio i -> Bool
~= Ratio i
y = Ratio i -> i
forall a. Integral a => Ratio a -> a
numerator Ratio i
x i -> i -> Bool
forall a. NearEq a => a -> a -> Bool
~= Ratio i -> i
forall a. Integral a => Ratio a -> a
numerator Ratio i
y Bool -> Bool -> Bool
&& Ratio i -> i
forall a. Integral a => Ratio a -> a
denominator Ratio i
x i -> i -> Bool
forall a. NearEq a => a -> a -> Bool
~= Ratio i -> i
forall a. Integral a => Ratio a -> a
denominator Ratio i
y
instance NearEq a => NearEq [a] where
  []   ~= :: [a] -> [a] -> Bool
~= []   = Bool
True
  a
x:[a]
xs ~= a
y:[a]
ys = a
x a -> a -> Bool
forall a. NearEq a => a -> a -> Bool
~= a
y Bool -> Bool -> Bool
&& [a]
xs [a] -> [a] -> Bool
forall a. NearEq a => a -> a -> Bool
~= [a]
ys
  [a]
_    ~= [a]
_    = Bool
False
instance NearEq a => NearEq (Maybe a) where
  Maybe a
Nothing ~= :: Maybe a -> Maybe a -> Bool
~= Maybe a
Nothing = Bool
True
  Just a
x  ~= Just a
y  = a
x a -> a -> Bool
forall a. NearEq a => a -> a -> Bool
~= a
y
  Maybe a
_       ~= Maybe a
_       = Bool
False
instance (NearEq a, NearEq b) => NearEq (Either a b) where
  Left  a
x ~= :: Either a b -> Either a b -> Bool
~= Left  a
y = a
x a -> a -> Bool
forall a. NearEq a => a -> a -> Bool
~= a
y
  Right b
x ~= Right b
y = b
x b -> b -> Bool
forall a. NearEq a => a -> a -> Bool
~= b
y
  Either a b
_       ~= Either a b
_       = Bool
False
instance (NearEq a, NearEq b) => NearEq (a,b) where
  (a
x1,b
x2) ~= :: (a, b) -> (a, b) -> Bool
~= (a
y1,b
y2) = a
x1 a -> a -> Bool
forall a. NearEq a => a -> a -> Bool
~= a
y1 Bool -> Bool -> Bool
&& b
x2 b -> b -> Bool
forall a. NearEq a => a -> a -> Bool
~= b
y2
instance (NearEq a, NearEq b, NearEq c) => NearEq (a,b,c) where
  (a
x1,b
x2,c
x3) ~= :: (a, b, c) -> (a, b, c) -> Bool
~= (a
y1,b
y2,c
y3) = a
x1 a -> a -> Bool
forall a. NearEq a => a -> a -> Bool
~= a
y1 Bool -> Bool -> Bool
&& b
x2 b -> b -> Bool
forall a. NearEq a => a -> a -> Bool
~= b
y2 Bool -> Bool -> Bool
&& c
x3 c -> c -> Bool
forall a. NearEq a => a -> a -> Bool
~= c
y3