packages feed

aern2-mp-0.1.4: src-rounded/AERN2/MP/Float/Conversions.hs

{-|
    Module      :  AERN2.MP.Float.Conversions
    Description :  Conversions and comparisons of arbitrary precision floats
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

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

    Conversions and comparisons of arbitrary precision floating point numbers
-}

module AERN2.MP.Float.Conversions
  (
   -- * MPFloat to other types (see also instances)
   toDouble
   -- * MPFloat constructors (see also instances)
   , CanBeMPFloat, mpFloat
   , fromIntegerCEDU
   , fromRationalCEDU
   -- * comparisons and constants (see also instances)
   , zero, one, two
   , nan, infinity
   )
where

import MixedTypesNumPrelude
import qualified Prelude as P

import Data.Ratio
import Data.Convertible

import AERN2.Norm
import AERN2.MP.Precision

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

import qualified AERN2.MP.Float.RoundedAdaptor as MPLow

mpToDouble :: MPLow.RoundMode -> MPFloat -> Double
mpToDouble = MPLow.toDoubleA

mpToRational :: MPFloat -> Rational
mpToRational x
  | x == 0 = 0.0
  | otherwise = MPLow.toRationalA x

mpFromRationalA :: MPLow.RoundMode -> MPLow.Precision -> Rational -> MPFloat
mpFromRationalA = MPLow.fromRationalA

{- conversions to MPFloat -}

type CanBeMPFloat t = ConvertibleExactly t MPFloat
mpFloat :: (CanBeMPFloat t) => t -> MPFloat
mpFloat = convertExactly

instance ConvertibleExactly Integer MPFloat where
    safeConvertExactly n =
        findExact $ map (flip fromIntegerCEDU n) $ standardPrecisions initPrec
        where
        initPrec =
            case getNormLog n of
              NormBits b -> prec (b + 8)
              _ -> prec 8
        findExact [] =
            convError "integer too high to represent exactly" n
        findExact (cedu : rest)
            | ceduErr cedu P.> zero = findExact rest
            | otherwise = Right (ceduCentre cedu)

instance ConvertibleExactly Int MPFloat where
    safeConvertExactly = safeConvertExactly . integer

fromIntegerCEDU :: Precision -> Integer -> BoundsCEDU MPFloat
fromIntegerCEDU pp n =
  constCEDU (\r p -> MPLow.fromIntegerA r p n) (p2mpfrPrec pp)

fromRationalCEDU :: Precision -> Rational -> BoundsCEDU MPFloat
fromRationalCEDU pp q =
  constCEDU (\r p -> mpFromRationalA r p q) (p2mpfrPrec pp)

{- conversions from MPFloat -}

instance ConvertibleExactly MPFloat Rational where
  safeConvertExactly = Right . mpToRational

toDouble :: MPFloat -> Double
toDouble = mpToDouble MPLow.Up

instance Convertible MPFloat Double where
  safeConvert x
    | isFinite dbl = Right dbl
    | otherwise = convError "conversion to double: out of bounds" x
    where
    dbl = toDouble x

instance CanRound MPFloat where
  properFraction x = (n,f)
    where
      r = rational x
      n = (numerator r) `P.quot` (denominator r)
      f = ceduCentre $ x `subCEDU` (mpFloat n)

{- comparisons -}

instance HasEqAsymmetric MPFloat MPFloat
instance HasEqAsymmetric MPFloat Integer where
  equalTo = convertSecond equalTo
instance HasEqAsymmetric Integer MPFloat where
  equalTo = convertFirst equalTo
instance HasEqAsymmetric MPFloat Int where
  equalTo = convertSecond equalTo
instance HasEqAsymmetric Int MPFloat where
  equalTo = convertFirst equalTo
instance HasEqAsymmetric MPFloat Rational where
  equalTo = convertFirst equalTo
instance HasEqAsymmetric Rational MPFloat where
  equalTo = convertSecond equalTo

instance CanTestZero MPFloat

instance HasOrderAsymmetric MPFloat MPFloat
instance HasOrderAsymmetric MPFloat Integer where
  lessThan = convertSecond lessThan
  leq = convertSecond leq
instance HasOrderAsymmetric Integer MPFloat where
  lessThan = convertFirst lessThan
  leq = convertFirst leq
instance HasOrderAsymmetric MPFloat Int where
  lessThan = convertSecond lessThan
  leq = convertSecond leq
instance HasOrderAsymmetric Int MPFloat where
  lessThan = convertFirst lessThan
  leq = convertFirst leq
instance HasOrderAsymmetric Rational MPFloat where
  lessThan = convertSecond lessThan
  leq = convertSecond leq
instance HasOrderAsymmetric MPFloat Rational where
  lessThan = convertFirst lessThan
  leq = convertFirst leq

instance CanTestPosNeg MPFloat

{- min, max -}

instance CanMinMaxAsymmetric MPFloat MPFloat

{- constants -}

zero, one, two :: MPFloat
zero = MPLow.zero
one = MPLow.one
two = MPLow.add MPLow.Up (MPLow.getPrec one) one one

nan, infinity :: MPFloat
nan = ceduCentre $ divCEDU zero zero 
infinity = ceduCentre $ divCEDU one zero 

itisNaN :: MPFloat -> Bool
itisNaN x = not $ x P.== x

itisInfinite :: MPFloat -> Bool
itisInfinite x =
  ceduCentre (mulCEDU x two) P.== x
  &&
  x P./= zero

instance CanTestFinite MPFloat where
  isInfinite = itisInfinite
  isFinite x = not (itisInfinite x || itisNaN x)

instance CanTestNaN MPFloat where
  isNaN = itisNaN