    -- |
    -- 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