packages feed

AERN-Real-2011.1: src/Numeric/AERN/RealArithmetic/Auxiliary.hs

{-|
    Module      :  Numeric.AERN.RealArithmetic.Auxiliary
    Description :  auxiliary generic operators and utilities  
    Copyright   :  (c) Michal Konecny, Jan Duracz
    License     :  BSD3

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

    Auxiliary generic operators and utilities.

    This is a hidden internal module.    
-}

module Numeric.AERN.RealArithmetic.Auxiliary where

import Numeric.AERN.RealArithmetic.ExactOps
import Numeric.AERN.Basics.Exception
import Numeric.AERN.Basics.Mutable

import Control.Exception
import Control.Monad.ST


powerFromMult :: 
    (HasOne t) =>
    (t -> t -> t) {-^ associative binary operation @*@ -} ->
    t {-^ @x@ -} ->
    Int {-^ @n@ positive -} ->
    t {-^ product @x * x * ... * x@ of @n@ copies of @x@ -}
powerFromMult mult x n
    | n < 0 = throw $ AERNException "powerFromMult does not support negative exponents"
    | otherwise = p n
    where
    p n
        | n == 0 = one
        | n == 1 = x
        | otherwise =
            case even n of
                True -> 
                    powHalf `mult` powHalf 
                False -> 
                    x `mult` (powHalf `mult` powHalf)
        where
        powHalf = p (n `div` 2)

powerFromMultInPlace :: 
    (HasOne t, CanBeMutable t) =>
    (Mutable t s -> Mutable t s -> Mutable t s -> ST s ()) {-^ associative binary operation @*@ -} ->
    (Mutable t s) {-^ where to put the resulting power @x^n@  -} ->
    (Mutable t s) {-^ @x@ -} ->
    Int {-^ @n@ positive -} ->
    ST s ()
powerFromMultInPlace mult rM xM n
    -- beware rM and xM may alias!
    | n < 0 = throw $ AERNException "powerFromMultInPlace does not support negative exponents"
    | otherwise =
        do
        nrM <- cloneMutable xM -- a non-aliased variable for interim results
        p nrM n -- nrM := x^n
        assignMutable rM nrM -- rM := nr
    where
    p nrM n -- ensures nrM holds x^n
        | n == 0 = writeMutable nrM one
        | n == 1 = return () -- assuming nrM already contains x
        | otherwise =
            case even n of
                True -> 
                    do
                    powHalf -- rM now holds x^(n/2)
                    mult nrM nrM nrM -- square rM
                False -> 
                    do
                    powHalf -- rM now holds x^(n-1/2)
                    mult nrM nrM nrM -- square rM
                    mult nrM nrM xM -- multiply by x one more time
        where
        rM = () -- avoid accidental use of rM from parent context
        powHalf = p nrM (n `div` 2)