module AERN2.MP.UseMPFR.ErrorBound
(ErrorBound, CanBeErrorBound, errorBound,
absMP, subMP)
where
import MixedTypesNumPrelude
import qualified Prelude as P
import Data.Typeable
import Test.QuickCheck
import Data.Convertible
import Math.NumberTheory.Logarithms (integerLog2)
import AERN2.MP.Precision
import AERN2.MP.Accuracy
import qualified AERN2.MP.UseMPFR.Float as MPFloat
import AERN2.MP.UseMPFR.Float (MPFloat, mpFloat, frequencyElements)
import AERN2.MP.UseMPFR.Float.Operators
import AERN2.MP.Dyadic
_example1 :: ErrorBound
_example1 = 2*((errorBound 0.01) + 0.1*(errorBound 0.01)/3)
newtype ErrorBound = ErrorBound { er2mp :: MPFloat }
deriving (P.Eq, P.Ord, Typeable)
instance Show ErrorBound where
show (ErrorBound d) = show d
errorBoundPrecision :: Precision
errorBoundPrecision = prec 53
instance HasAccuracy ErrorBound where
getAccuracy (ErrorBound e)
| eN > 0 =
bits $ negate $ integerLog2 eN
| e > 0 && eRecipN > 0 =
bits $ integerLog2 eRecipN
| e == 0 = Exact
| otherwise = NoInformation
where
eN = floor $ rational e
eRecipN = ceiling $ rational $ MPFloat.recipDown e
instance ConvertibleExactly ErrorBound MPFloat where
safeConvertExactly = Right . er2mp
instance ConvertibleExactly ErrorBound Dyadic where
safeConvertExactly = Right . dyadic . er2mp
instance ConvertibleExactly ErrorBound Rational where
safeConvertExactly = Right . convertExactly . mpFloat
type CanBeErrorBound t = Convertible t ErrorBound
errorBound :: (CanBeErrorBound t) => t -> ErrorBound
errorBound = convert
instance Convertible Rational ErrorBound where
safeConvert x
| x >= 0 = Right $ ErrorBound $ MPFloat.fromRationalUp errorBoundPrecision x
| otherwise = convError "Trying to construct a negative ErrorBound" x
instance Convertible MPFloat ErrorBound where
safeConvert x
| x >= 0 = Right $ ErrorBound $ MPFloat.setPrecisionUp errorBoundPrecision x
| otherwise = convError "Trying to construct a negative ErrorBound" x
instance Convertible Integer ErrorBound where
safeConvert x
| x >= 0 = Right $ ErrorBound $ MPFloat.fromIntegerUp errorBoundPrecision x
| otherwise = convError "Trying to construct a negative ErrorBound" x
instance Convertible Int ErrorBound where
safeConvert = safeConvert . integer
instance HasOrderAsymmetric ErrorBound ErrorBound
instance HasOrderAsymmetric ErrorBound MPFloat where
lessThan = convertFirst lessThan
leq = convertFirst leq
instance HasOrderAsymmetric MPFloat ErrorBound where
lessThan = convertSecond lessThan
leq = convertSecond leq
instance HasEqAsymmetric ErrorBound Rational where
equalTo = convertFirst equalTo
instance HasEqAsymmetric Rational ErrorBound where
equalTo = convertSecond equalTo
instance HasOrderAsymmetric ErrorBound Rational where
lessThan = convertFirst lessThan
leq = convertFirst leq
instance HasOrderAsymmetric Rational ErrorBound where
lessThan = convertSecond lessThan
leq = convertSecond leq
instance HasEqAsymmetric ErrorBound Integer where
equalTo a b = equalTo (dyadic a) (dyadic b)
instance HasEqAsymmetric Integer ErrorBound where
equalTo a b = equalTo (dyadic a) (dyadic b)
instance HasOrderAsymmetric ErrorBound Integer where
lessThan a b = lessThan (dyadic a) (dyadic b)
leq a b = leq (dyadic a) (dyadic b)
instance HasOrderAsymmetric Integer ErrorBound where
lessThan a b = lessThan (dyadic a) (dyadic b)
leq a b = leq (dyadic a) (dyadic b)
instance HasEqAsymmetric ErrorBound Int where
equalTo a b = equalTo (dyadic a) (dyadic b)
instance HasEqAsymmetric Int ErrorBound where
equalTo a b = equalTo (dyadic a) (dyadic b)
instance HasOrderAsymmetric ErrorBound Int where
lessThan a b = lessThan (dyadic a) (dyadic b)
leq a b = leq (dyadic a) (dyadic b)
instance HasOrderAsymmetric Int ErrorBound where
lessThan a b = lessThan (dyadic a) (dyadic b)
leq a b = leq (dyadic a) (dyadic b)
instance CanMinMaxAsymmetric ErrorBound ErrorBound
subMP :: MPFloat -> MPFloat -> ErrorBound
a `subMP` b = errorBound $ a -^ b
absMP :: MPFloat -> ErrorBound
absMP = errorBound . abs
instance CanAddAsymmetric ErrorBound ErrorBound where
add (ErrorBound a) (ErrorBound b) = ErrorBound $ a +^ b
instance CanAddAsymmetric ErrorBound MPFloat where
type AddType ErrorBound MPFloat = ErrorBound
add = convertSecondUsing (\ _ f -> convert f) add
instance CanAddAsymmetric MPFloat ErrorBound where
type AddType MPFloat ErrorBound = ErrorBound
add = convertFirstUsing (\ f _ -> convert f) add
instance CanMulAsymmetric ErrorBound ErrorBound where
mul (ErrorBound a) (ErrorBound b) = ErrorBound $ a *^ b
instance CanMulAsymmetric ErrorBound MPFloat where
type MulType ErrorBound MPFloat = ErrorBound
mul = convertSecondUsing (\ _ f -> convert f) mul
instance CanMulAsymmetric MPFloat ErrorBound where
type MulType MPFloat ErrorBound = ErrorBound
mul = convertFirstUsing (\ f _ -> convert f) mul
instance CanMulAsymmetric ErrorBound Integer where
type MulType ErrorBound Integer = ErrorBound
mul (ErrorBound a) i
| i >= 0 = ErrorBound $ a *^ (MPFloat.fromIntegerUp errorBoundPrecision i)
| otherwise = error "trying to multiply ErrorBound by a negative integer"
instance CanMulAsymmetric Integer ErrorBound where
type MulType Integer ErrorBound = ErrorBound
mul i (ErrorBound b)
| i >= 0 = ErrorBound $ (MPFloat.fromIntegerUp errorBoundPrecision i) *^ b
| otherwise = error "trying to multiply ErrorBound by a negative integer"
instance CanMulAsymmetric ErrorBound Rational where
type MulType ErrorBound Rational = ErrorBound
mul (ErrorBound a) r
| r >= 0.0 = ErrorBound $ a *^ (MPFloat.fromRationalUp errorBoundPrecision r)
| otherwise = error "trying to multiply ErrorBound by a negative integer"
instance CanMulAsymmetric Rational ErrorBound where
type MulType Rational ErrorBound = ErrorBound
mul r (ErrorBound b)
| r >= 0.0 = ErrorBound $ (MPFloat.fromRationalUp errorBoundPrecision r) *^ b
| otherwise = error "trying to multiply ErrorBound by a negative integer"
instance CanDiv ErrorBound Integer where
type DivTypeNoCN ErrorBound Integer = ErrorBound
type DivType ErrorBound Integer = ErrorBound
divideNoCN = divide
divide (ErrorBound a) i
| i > 0 = ErrorBound $ a /^ (MPFloat.fromIntegerUp errorBoundPrecision i)
| otherwise = error "trying to multiply ErrorBound by a non-positive integer"
instance Arbitrary ErrorBound where
arbitrary =
do
giveSpecialValue <- frequencyElements [(5, False),(1, True)]
aux giveSpecialValue
where
aux giveSpecialValue
| giveSpecialValue =
elements (map convert [0.0,0.0,0.0,10.0,1.0,0.5,0.125])
| otherwise =
do
(s :: Integer) <- arbitrary
let resultR = ((abs s) `mod` (2^!35))/!(2^!32)
let result = convert resultR
return result