{-# OPTIONS_GHC -Wno-orphans #-}
{-|
    Module      :  AERN2.MP.Float.Arithmetic
    Description :  Arbitrary precision floating point numbers
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable

    Arbitrary precision floating-point numbers with up/down-rounded operations.
-}
module AERN2.MP.Float.Arithmetic
  (
   -- * MPFloat basic arithmetic
     addCEDU, subCEDU
   , mulCEDU, divCEDU, recipCEDU
   -- * MPFloat selected constants and operations
   , piCEDU
   , cosCEDU, sinCEDU
   , sqrtCEDU, expCEDU, logCEDU
   )
where

import MixedTypesNumPrelude
import qualified Prelude as P

import AERN2.MP.Precision

import qualified Data.CDAR as MPLow

import AERN2.MP.Float.Auxi
import AERN2.MP.Float.Type

{- common functions -}

instance CanNeg MPFloat where
  negate :: MPFloat -> NegType MPFloat
negate = (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
forall a. Num a => a -> a
P.negate

instance CanAbs MPFloat where
  abs :: MPFloat -> AbsType MPFloat
abs = (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
forall a. Num a => a -> a
P.abs

addCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
addCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
addCEDU = (MPFloat -> MPFloat -> MPFloat)
-> MPFloat -> MPFloat -> BoundsCEDU MPFloat
binaryCEDU ((MPFloat -> MPFloat -> MPFloat)
 -> MPFloat -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat -> MPFloat)
-> MPFloat
-> MPFloat
-> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx -> Approx) -> MPFloat -> MPFloat -> MPFloat
lift2 Approx -> Approx -> Approx
forall a. Num a => a -> a -> a
(P.+)

subCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
subCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
subCEDU = (MPFloat -> MPFloat -> MPFloat)
-> MPFloat -> MPFloat -> BoundsCEDU MPFloat
binaryCEDU ((MPFloat -> MPFloat -> MPFloat)
 -> MPFloat -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat -> MPFloat)
-> MPFloat
-> MPFloat
-> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx -> Approx) -> MPFloat -> MPFloat -> MPFloat
lift2 Approx -> Approx -> Approx
forall a. Num a => a -> a -> a
(P.-)

mulCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
mulCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
mulCEDU = (MPFloat -> MPFloat -> MPFloat)
-> MPFloat -> MPFloat -> BoundsCEDU MPFloat
binaryCEDU ((MPFloat -> MPFloat -> MPFloat)
 -> MPFloat -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat -> MPFloat)
-> MPFloat
-> MPFloat
-> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx -> Approx) -> MPFloat -> MPFloat -> MPFloat
lift2 Approx -> Approx -> Approx
forall a. Num a => a -> a -> a
(P.*)

divCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
divCEDU :: MPFloat -> MPFloat -> BoundsCEDU MPFloat
divCEDU MPFloat
x MPFloat
y 
    | MPFloat -> Approx
unMPFloat MPFloat
y Approx -> Approx -> Bool
forall a. Eq a => a -> a -> Bool
P.== (Integer -> Approx
forall a. Num a => Integer -> a
P.fromInteger Integer
0) = MPFloat -> BoundsCEDU MPFloat
getBoundsCEDU (Approx -> MPFloat
MPFloat Approx
MPLow.Bottom)
    | Bool
otherwise = (MPFloat -> MPFloat -> MPFloat)
-> MPFloat -> MPFloat -> BoundsCEDU MPFloat
binaryCEDU ((Approx -> Approx -> Approx) -> MPFloat -> MPFloat -> MPFloat
lift2 Approx -> Approx -> Approx
forall a. Fractional a => a -> a -> a
(P./)) MPFloat
x MPFloat
y

recipCEDU :: MPFloat -> BoundsCEDU MPFloat
recipCEDU :: MPFloat -> BoundsCEDU MPFloat
recipCEDU = (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU ((MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
forall a. Fractional a => a -> a
P.recip

{- special constants and functions -}

piCEDU :: Precision -> BoundsCEDU MPFloat
piCEDU :: Precision -> BoundsCEDU MPFloat
piCEDU Precision
pp = 
    MPFloat -> BoundsCEDU MPFloat
getBoundsCEDU (MPFloat -> BoundsCEDU MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ Approx -> MPFloat
MPFloat (Precision -> Approx
MPLow.piA (Precision -> Precision
p2cdarPrec Precision
pp))

cosCEDU :: MPFloat -> BoundsCEDU MPFloat
cosCEDU :: MPFloat -> BoundsCEDU MPFloat
cosCEDU = (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU ((MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
MPLow.cosA

sinCEDU :: MPFloat -> BoundsCEDU MPFloat
sinCEDU :: MPFloat -> BoundsCEDU MPFloat
sinCEDU = (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU ((MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
MPLow.sinA
            
sqrtCEDU :: MPFloat -> BoundsCEDU MPFloat
sqrtCEDU :: MPFloat -> BoundsCEDU MPFloat
sqrtCEDU = (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU ((MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
MPLow.sqrtA
            
expCEDU :: MPFloat -> BoundsCEDU MPFloat
expCEDU :: MPFloat -> BoundsCEDU MPFloat
expCEDU = (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU ((MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
MPLow.expA

logCEDU :: MPFloat -> BoundsCEDU MPFloat
logCEDU :: MPFloat -> BoundsCEDU MPFloat
logCEDU = (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU ((MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat)
-> (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ (Approx -> Approx) -> MPFloat -> MPFloat
lift1 Approx -> Approx
MPLow.logA

{- auxiliary functions to automatically determine result precision from operand precisions -}

binaryCEDU ::
    (MPFloat -> MPFloat -> MPFloat) ->
    (MPFloat -> MPFloat -> BoundsCEDU MPFloat)
binaryCEDU :: (MPFloat -> MPFloat -> MPFloat)
-> MPFloat -> MPFloat -> BoundsCEDU MPFloat
binaryCEDU MPFloat -> MPFloat -> MPFloat
op MPFloat
x MPFloat
y =
    MPFloat -> BoundsCEDU MPFloat
getBoundsCEDU (MPFloat -> BoundsCEDU MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ MPFloat -> MPFloat -> MPFloat
op MPFloat
x MPFloat
y

unaryCEDU ::
    (MPFloat -> MPFloat) ->
    (MPFloat -> BoundsCEDU MPFloat)
unaryCEDU :: (MPFloat -> MPFloat) -> MPFloat -> BoundsCEDU MPFloat
unaryCEDU MPFloat -> MPFloat
op MPFloat
x =
    MPFloat -> BoundsCEDU MPFloat
getBoundsCEDU (MPFloat -> BoundsCEDU MPFloat) -> MPFloat -> BoundsCEDU MPFloat
forall a b. (a -> b) -> a -> b
$ MPFloat -> MPFloat
op MPFloat
x

-- unaryPrecCEDU ::
--     Integer ->
--     (MPLow.Precision -> MPFloat -> MPFloat) ->
--     (MPFloat -> BoundsCEDU MPFloat)
-- unaryPrecCEDU addPrec op x@(MPLow.Approx mb _ _ s) =
--     getBoundsCEDU $ op ((-s P.+ mb) P.+ (int addPrec)) x
-- unaryPrecCEDU addPrec op MPLow.Bottom =
--     getBoundsCEDU $ op ((int $ integer defaultPrecision) P.+ (int addPrec)) MPLow.Bottom