aern2-mp-0.2.4.0: src/AERN2/MP/Ball/Elementary.hs
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-|
Module : AERN2.MP.Ball.Elementary
Description : Elementary operations on arbitrary precision dyadic balls
Copyright : (c) Michal Konecny
License : BSD3
Maintainer : mikkonecny@gmail.com
Stability : experimental
Portability : portable
Elementary operations on arbitrary precision dyadic balls
-}
module AERN2.MP.Ball.Elementary
(
-- * Ball operations (see also instances)
piBallP
-- * Helpers for constructing ball functions
, fromApproxWithLipschitz
)
where
import MixedTypesNumPrelude
import qualified Prelude as P
import AERN2.Normalize
import AERN2.MP.Dyadic (Dyadic)
import qualified AERN2.MP.Float as MPFloat
import AERN2.MP.Float (MPFloat, mpFloat, ceduCentreErr)
-- import AERN2.MP.Float.Operators
import AERN2.MP.Precision
-- import qualified AERN2.MP.ErrorBound as EB
import AERN2.MP.ErrorBound (errorBound)
import AERN2.MP.Ball.Type
import AERN2.MP.Ball.Conversions ()
import AERN2.MP.Ball.Comparisons ()
import AERN2.MP.Ball.Field (mulByEndpoints)
{- trigonometrics -}
piBallP :: Precision -> MPBall
piBallP p = MPBall piC (errorBound piErr)
where
(piC, piErr) = MPFloat.ceduCentreErr $ MPFloat.piCEDU p
instance CanSinCos MPBall where
sin = sinB 1
cos = cosB 1
sinB :: Integer -> MPBall -> MPBall
sinB i x =
-- increasingPrecisionUntilNotImproving (fromApproxWithLipschitz MPFloat.sinDown MPFloat.sinUp lip) x
max (-1) $ min 1 $
fromApproxWithLipschitz MPFloat.sinCEDU lip x
where
lip
| i == 0 = mpFloat 1
| otherwise = endpointR $ abs $ cosB (i - 1) x
cosB :: Integer -> MPBall -> MPBall
cosB i x =
-- increasingPrecisionUntilNotImproving (fromApproxWithLipschitz MPFloat.cosDown MPFloat.cosUp lip) x
max (-1) $ min 1 $
fromApproxWithLipschitz MPFloat.cosCEDU lip x
where
lip
| i == 0 = mpFloat 1
| otherwise = endpointR $ abs $ sinB (i - 1) x
-- increasingPrecisionUntilNotImproving :: (MPBall -> MPBall) -> (MPBall -> MPBall)
-- increasingPrecisionUntilNotImproving f x =
-- waitUntilNotImproving $ map aux (precisions xPrec (xPrec*2))
-- where
-- xPrec = getPrecision x
-- precisions p1 p2 = p1 : (precisions p2 (p1 + p2))
-- aux p = f $ setPrecision p x
-- waitUntilNotImproving xx@(x1:_) = aux2 (getAccuracy x1) xx
-- waitUntilNotImproving _ = error "AERN2.MP.Ball.Elementary: internal error in increasingPrecisionUntilNotImproving"
-- aux2 x1AC (x1:x2:rest)
-- | x1AC < x2AC = aux2 x2AC (x2:rest)
-- | otherwise = x1
-- where
-- x2AC = getAccuracy x2
-- aux2 _ _ = error "AERN2.MP.Ball.Elementary: internal error in increasingPrecisionUntilNotImproving"
{- exp, log, power -}
instance CanExp MPBall where
exp = intervalFunctionByEndpointsUpDown MPFloat.expDown MPFloat.expUp
instance CanLog MPBall where
type LogType MPBall = MPBall
log x
| x_!>! 1 =
setPrecision p $ ballFunctionUsingLipschitz log_ logLip x_
| x_!>! 0 =
setPrecision p $ intervalFunctionByEndpoints log_ x_
| x !>! 0 =
intervalFunctionByEndpoints log_ x
| otherwise = err
where
p = getPrecision x
x_ = reducePrecionIfInaccurate x
err = error $ "log: argument must be > 0: " ++ show x
log_ (MPBall c e) = MPBall lc (e + (errorBound le))
where
(lc, le) = ceduCentreErr $ MPFloat.logCEDU c
logLip y = errorBound $ (1/y)
instance CanPow MPBall MPBall where
pow = powUsingExpLog (mpBall 1) mulByEndpoints recip
instance CanPow MPBall Dyadic where
pow b e = pow b (mpBall e)
instance CanPow MPBall Rational where
pow b e = pow b (mpBallP (getPrecision b) e)
instance CanSqrt MPBall where
type SqrtType MPBall = MPBall
sqrt x
| x !>=! 0 = aux x
| x ?>=? 0 = aux $ max 0 x
| otherwise = err
where
aux =
intervalFunctionByEndpointsUpDown
(\ e -> MPFloat.sqrtDown (P.max (mpFloat 0) e))
(\ e -> MPFloat.sqrtUp (P.max (mpFloat 0) e))
err = error $ "sqrt: argument must be >= 0: " ++ show x
{- generic methods for computing real functions from MPFR-approximations -}
{-|
Computes a real function @f@ from correctly rounded MPFR-approximations and a number @lip@ which is a
Lipschitz constant for @f@, i.e. @|f(x) - f(y)| <= lip * |x - y|@ for all @x@,@y@.
-}
fromApproxWithLipschitz ::
(MPFloat -> MPFloat.BoundsCEDU MPFloat) {-^ @fCEDU@: a version of @f@ on MPFloat returning rigorous bounds -} ->
MPFloat {-^ @lip@ a Lipschitz constant for @f@, @lip > 0@ -} ->
(MPBall -> MPBall) {-^ @f@ on MPBall rounding *outwards* -}
fromApproxWithLipschitz fCEDU lip _x@(MPBall xc xe) =
normalize $ MPBall fxCP err
where
(fxC, fxErr) = MPFloat.ceduCentreErr $ fCEDU xc
(MPBall fxCP fxe) =
setPrecision (getPrecision xc) $ -- beware, some MPFloat functions may increase precision, eg sine and cosine
(MPBall fxC (errorBound fxErr))
err = (errorBound lip) * xe + fxe
$(declForTypes
[[t| Integer |], [t| Int |], [t| Rational |]]
(\ b -> [d|
instance
CanPow $b MPBall
where
type PowType $b MPBall = MPBall
pow x e = pow (mpBallP (getPrecision e) x) e
|]))