-- |
-- The module contains arithmetic calculations according the IEEE 754 standard
-- for plus, minus, unary minus, multiplication, modulo and division.
--


module Text.XML.HXT.XPath.XPathArithmetic
    ( xPathMulti
    , xPathMod
    , xPathDiv
    , xPathAdd
    , xPathUnary
    )
where

import Text.XML.HXT.XPath.XPathDataTypes


-- |
-- Unary minus: the value 'NaN' is not calculatable and returned unchanged,
-- all other values can be denied.
--

xPathUnary :: XPathFilter
xPathUnary :: XPathFilter
xPathUnary (XPVNumber (Float Float
f)) =  XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (-Float
f))
xPathUnary (XPVError String
e)          = String -> XPathValue
XPVError String
e
xPathUnary (XPVNumber XPNumber
NaN)       = XPNumber -> XPathValue
XPVNumber XPNumber
NaN
xPathUnary (XPVNumber XPNumber
Pos0)      = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathUnary (XPVNumber XPNumber
Neg0)      = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
xPathUnary (XPVNumber XPNumber
PosInf)    = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathUnary (XPVNumber XPNumber
NegInf)    = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathUnary XPathValue
_                     = String -> XPathValue
XPVError String
"Call to unaryEval without a number"


-- |
-- Multiplication
--

xPathMulti :: Op -> XPathValue -> XPathFilter
xPathMulti :: Op -> XPathValue -> XPathFilter
xPathMulti Op
_ (XPVNumber (Float Float
a)) (XPVNumber (Float Float
b))
    = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
b))
xPathMulti Op
_ (XPVNumber XPNumber
NegInf) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathMulti Op
_ (XPVNumber XPNumber
PosInf) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathMulti Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
NegInf)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathMulti Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
PosInf)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathMulti Op
_ (XPVNumber XPNumber
Pos0) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
xPathMulti Op
_ (XPVNumber XPNumber
Neg0) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathMulti Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
Pos0)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
xPathMulti Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
Neg0)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathMulti Op
a XPathValue
b XPathValue
c = Op -> XPathValue -> XPathFilter
xPathSpez Op
a XPathValue
b XPathValue
c


-- |
-- Modulo
--

xPathMod :: Op -> XPathValue -> XPathFilter
xPathMod :: Op -> XPathValue -> XPathFilter
xPathMod Op
_ (XPVNumber (Float Float
a)) (XPVNumber (Float Float
b))
    | Float -> Float -> Float
forall {a}. RealFrac a => a -> a -> a
floatMod Float
a Float
b Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
== Float
0 = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (Float -> Float -> Float
forall {a}. RealFrac a => a -> a -> a
floatMod Float
a Float
b))
      where
      floatMod :: a -> a -> a
floatMod a
x a
y
        | a
xa -> a -> a
forall a. Fractional a => a -> a -> a
/a
y a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 = a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
y a -> a -> a
forall a. Num a => a -> a -> a
* Integer -> a
forall a. Num a => Integer -> a
fromInteger(a -> Integer
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
y))
        | Bool
otherwise =a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
y a -> a -> a
forall a. Num a => a -> a -> a
* Integer -> a
forall a. Num a => Integer -> a
fromInteger(a -> Integer
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
y))

xPathMod Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
NegInf)
    = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float Float
a)
xPathMod Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
PosInf)
    = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float Float
a)
xPathMod Op
_ (XPVNumber XPNumber
Neg0) (XPVNumber XPNumber
Pos0)
    = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathMod Op
a XPathValue
b XPathValue
c = Op -> XPathValue -> XPathFilter
xPathSpez Op
a XPathValue
b XPathValue
c


-- |
-- Division: the divison-operator is not according the IEEE 754 standard,
-- it calculates the same as the % operator in Java and ECMAScript
--

xPathDiv :: Op -> XPathValue -> XPathFilter
xPathDiv :: Op -> XPathValue -> XPathFilter
xPathDiv Op
_ (XPVNumber (Float Float
a)) (XPVNumber (Float Float
b))
    = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (Float
a Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
b))
xPathDiv Op
_ (XPVNumber XPNumber
NegInf) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathDiv Op
_ (XPVNumber XPNumber
PosInf) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathDiv Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
NegInf)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathDiv Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
PosInf)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
xPathDiv Op
_ (XPVNumber XPNumber
Neg0) (XPVNumber (Float Float
a))
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathDiv Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
Neg0)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathDiv Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
Pos0)
    | Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0     = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
    | Bool
otherwise = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathDiv Op
a XPathValue
b XPathValue
c  = Op -> XPathValue -> XPathFilter
xPathSpez Op
a XPathValue
b XPathValue
c


-- |
-- Plus and minus
--
--    1.parameter op :  plus or minus operation
--

xPathAdd :: Op -> XPathValue -> XPathFilter
xPathAdd :: Op -> XPathValue -> XPathFilter
xPathAdd Op
Plus (XPVNumber (Float Float
a)) (XPVNumber (Float Float
b))
    = if Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
b Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
== Float
0
        then XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
        else XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (Float
aFloat -> Float -> Float
forall a. Num a => a -> a -> a
+Float
b))
xPathAdd Op
Minus (XPVNumber (Float Float
a)) (XPVNumber (Float Float
b))
    = if Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
b Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
== Float
0
        then XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
        else XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (Float
aFloat -> Float -> Float
forall a. Num a => a -> a -> a
-Float
b))
xPathAdd Op
_ (XPVNumber XPNumber
PosInf) (XPVNumber XPNumber
NegInf)  = XPNumber -> XPathValue
XPVNumber XPNumber
NaN
xPathAdd Op
_ (XPVNumber XPNumber
NegInf) (XPVNumber XPNumber
PosInf)  = XPNumber -> XPathValue
XPVNumber XPNumber
NaN
xPathAdd Op
_ (XPVNumber XPNumber
PosInf) XPathValue
_                   = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathAdd Op
_ (XPVNumber XPNumber
NegInf) XPathValue
_                   = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathAdd Op
_ XPathValue
_ (XPVNumber XPNumber
PosInf)                   = XPNumber -> XPathValue
XPVNumber XPNumber
PosInf
xPathAdd Op
_ XPathValue
_ (XPVNumber XPNumber
NegInf)                   = XPNumber -> XPathValue
XPVNumber XPNumber
NegInf
xPathAdd Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
Pos0) = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float Float
a)
xPathAdd Op
op (XPVNumber XPNumber
Pos0) (XPVNumber (Float Float
a))
    | Op
op Op -> Op -> Bool
forall a. Eq a => a -> a -> Bool
== Op
Minus = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (-Float
a))
    | Bool
otherwise   = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float Float
a)
xPathAdd Op
op (XPVNumber XPNumber
Neg0) (XPVNumber (Float Float
a))
    | Op
op Op -> Op -> Bool
forall a. Eq a => a -> a -> Bool
== Op
Minus = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float (-Float
a))
    | Bool
otherwise   = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float Float
a)
xPathAdd Op
_ (XPVNumber (Float Float
a)) (XPVNumber XPNumber
Neg0) = XPNumber -> XPathValue
XPVNumber (Float -> XPNumber
Float Float
a)
xPathAdd Op
_ (XPVNumber XPNumber
Neg0) (XPVNumber XPNumber
Pos0)      = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathAdd Op
_ (XPVNumber XPNumber
Pos0) (XPVNumber XPNumber
Neg0)      = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathAdd Op
_ (XPVNumber XPNumber
Neg0) (XPVNumber XPNumber
Neg0)      = XPNumber -> XPathValue
XPVNumber XPNumber
Neg0
xPathAdd Op
_ (XPVNumber XPNumber
Pos0) (XPVNumber XPNumber
Pos0)      = XPNumber -> XPathValue
XPVNumber XPNumber
Pos0
xPathAdd Op
a XPathValue
b XPathValue
c = Op -> XPathValue -> XPathFilter
xPathSpez Op
a XPathValue
b XPathValue
c


-- |
-- Identically results of the operators are combined to get
-- as few as possible combinations of the special IEEE values
--
xPathSpez :: Op -> XPathValue -> XPathFilter
xPathSpez :: Op -> XPathValue -> XPathFilter
xPathSpez Op
_ (XPVError String
e) XPathValue
_ = String -> XPathValue
XPVError String
e
xPathSpez Op
_ XPathValue
_ (XPVError String
e) = String -> XPathValue
XPVError String
e
xPathSpez Op
_ XPathValue
_ XPathValue
_            = XPNumber -> XPathValue
XPVNumber XPNumber
NaN