# LANGUAGE CPP #
# LANGUAGE ForeignFunctionInterface #
--------------------------------------------------------------------
-- |
  Copyright :   ( c )   2013
-- License   :  BSD3
  Maintainer :     <  >
-- Stability :  experimental
-- Portability: non-portable
--
-- These functions provide wildly inaccurate but very fast
-- approximations to common transcendental functions.
--
  The algorithms here are based on    optimized ' pow ' ,
-- <-pow-approximation-for-java-and-c-c/>
-- which is in turn based on
-- <>
--------------------------------------------------------------------
module Data.Approximate.Numerics
  ( Fast(..)
  , blog
  ) where

class Floating a => Fast a where
  -- | Calculate an approximate log.
  flog    :: a -> a
  flog_lb :: a -> a
  flog_ub :: a -> a
  -- | Calculate an approximate exp.
  fexp    :: a -> a
  fexp_lb :: a -> a
  fexp_ub :: a -> a
  -- | Calculate an approximate pow.
  fpow    :: a -> a -> a
  fpow_lb :: a -> a -> a
  fpow_ub :: a -> a -> a

instance Fast Float where
  flog     = logf_fast
  flog_lb  = logf_fast_lb
  flog_ub  = logf_fast_ub
  fexp     = better_expf_fast
  fexp_lb  = expf_fast_lb
  fexp_ub  = expf_fast_ub
  fpow     = better_powf_fast_precise
  fpow_lb  = powf_fast_lb
  fpow_ub  = powf_fast_ub

instance Fast Double where
  flog     = log_fast
  flog_lb  = log_fast_lb
  flog_ub  = log_fast_ub
  fexp     = better_exp_fast
  fexp_lb  = exp_fast_lb
  fexp_ub  = exp_fast_ub
  fpow     = better_pow_fast_precise
  fpow_lb  = pow_fast_lb
  fpow_ub  = pow_fast_ub

  | Borchardt ’s Algorithm from “ Dead Reckoning : Calculating without instruments ” .
--
-- This is a remarkably bad approximate logarithm.
--
-- 'flog' had better outperform it! It is provided merely for comparison.
blog :: Floating a => a -> a
blog x = 6 * (x - 1) / (x + 1 + 4 * sqrt x)
  6 / ( x + 1 + 4 * sqrt x ) / ( x-1 ) -- herbie 's suggested replacement .
#ifdef HERBIE
# ANN blog "  " #
#endif

foreign import ccall unsafe pow_fast_lb       :: Double -> Double -> Double
foreign import ccall unsafe pow_fast_ub       :: Double -> Double -> Double
foreign import ccall unsafe better_pow_fast_precise  :: Double -> Double -> Double
foreign import ccall unsafe powf_fast_lb      :: Float -> Float -> Float
foreign import ccall unsafe powf_fast_ub      :: Float -> Float -> Float
foreign import ccall unsafe better_powf_fast_precise :: Float -> Float -> Float

foreign import ccall unsafe better_exp_fast   :: Double -> Double
foreign import ccall unsafe exp_fast_lb       :: Double -> Double
foreign import ccall unsafe exp_fast_ub       :: Double -> Double
foreign import ccall unsafe better_expf_fast  :: Float -> Float
foreign import ccall unsafe expf_fast_lb      :: Float -> Float
foreign import ccall unsafe expf_fast_ub      :: Float -> Float

foreign import ccall unsafe log_fast        :: Double -> Double
foreign import ccall unsafe log_fast_lb     :: Double -> Double
foreign import ccall unsafe log_fast_ub     :: Double -> Double
foreign import ccall unsafe logf_fast       :: Float -> Float
foreign import ccall unsafe logf_fast_lb    :: Float -> Float
foreign import ccall unsafe logf_fast_ub    :: Float -> Float

------------------------------------------------------------------
 |
 License   :  BSD3
 Stability :  experimental
 Portability: non-portable

 These functions provide wildly inaccurate but very fast
 approximations to common transcendental functions.

 <-pow-approximation-for-java-and-c-c/>
 which is in turn based on
 <>
------------------------------------------------------------------
 | Calculate an approximate log.
 | Calculate an approximate exp.
 | Calculate an approximate pow.

 This is a remarkably bad approximate logarithm.

 'flog' had better outperform it! It is provided merely for comparison.
 herbie 's suggested replacement .
# LANGUAGE CPP #
# LANGUAGE ForeignFunctionInterface #
  Copyright :   ( c )   2013
  Maintainer :     <  >
  The algorithms here are based on    optimized ' pow ' ,
module Data.Approximate.Numerics
  ( Fast(..)
  , blog
  ) where

class Floating a => Fast a where
  flog    :: a -> a
  flog_lb :: a -> a
  flog_ub :: a -> a
  fexp    :: a -> a
  fexp_lb :: a -> a
  fexp_ub :: a -> a
  fpow    :: a -> a -> a
  fpow_lb :: a -> a -> a
  fpow_ub :: a -> a -> a

instance Fast Float where
  flog     = logf_fast
  flog_lb  = logf_fast_lb
  flog_ub  = logf_fast_ub
  fexp     = better_expf_fast
  fexp_lb  = expf_fast_lb
  fexp_ub  = expf_fast_ub
  fpow     = better_powf_fast_precise
  fpow_lb  = powf_fast_lb
  fpow_ub  = powf_fast_ub

instance Fast Double where
  flog     = log_fast
  flog_lb  = log_fast_lb
  flog_ub  = log_fast_ub
  fexp     = better_exp_fast
  fexp_lb  = exp_fast_lb
  fexp_ub  = exp_fast_ub
  fpow     = better_pow_fast_precise
  fpow_lb  = pow_fast_lb
  fpow_ub  = pow_fast_ub

  | Borchardt ’s Algorithm from “ Dead Reckoning : Calculating without instruments ” .
blog :: Floating a => a -> a
blog x = 6 * (x - 1) / (x + 1 + 4 * sqrt x)
#ifdef HERBIE
# ANN blog "  " #
#endif

foreign import ccall unsafe pow_fast_lb       :: Double -> Double -> Double
foreign import ccall unsafe pow_fast_ub       :: Double -> Double -> Double
foreign import ccall unsafe better_pow_fast_precise  :: Double -> Double -> Double
foreign import ccall unsafe powf_fast_lb      :: Float -> Float -> Float
foreign import ccall unsafe powf_fast_ub      :: Float -> Float -> Float
foreign import ccall unsafe better_powf_fast_precise :: Float -> Float -> Float

foreign import ccall unsafe better_exp_fast   :: Double -> Double
foreign import ccall unsafe exp_fast_lb       :: Double -> Double
foreign import ccall unsafe exp_fast_ub       :: Double -> Double
foreign import ccall unsafe better_expf_fast  :: Float -> Float
foreign import ccall unsafe expf_fast_lb      :: Float -> Float
foreign import ccall unsafe expf_fast_ub      :: Float -> Float

foreign import ccall unsafe log_fast        :: Double -> Double
foreign import ccall unsafe log_fast_lb     :: Double -> Double
foreign import ccall unsafe log_fast_ub     :: Double -> Double
foreign import ccall unsafe logf_fast       :: Float -> Float
foreign import ccall unsafe logf_fast_lb    :: Float -> Float
foreign import ccall unsafe logf_fast_ub    :: Float -> Float
