{-
 - Copyright (C) 2009-2010 Nick Bowler.
 -
 - License BSD2:  2-clause BSD license.  See LICENSE for full terms.
 - This is free software: you are free to change and redistribute it.
 - There is NO WARRANTY, to the extent permitted by law.
 -}

-- | Bindings to the standard C math library.
{-# LANGUAGE ForeignFunctionInterface #-}
module Data.Floating.CMath (
    -- * Trigonometric functions
    c_acos, c_acosf, c_asin, c_asinf, c_atan, c_atanf, c_atan2, c_atan2f,
    c_cos, c_cosf, c_sin, c_sinf, c_tan, c_tanf,

    -- * Hyperbolic functions
    c_acosh, c_acoshf, c_asinh, c_asinhf, c_atanh, c_atanhf, c_cosh, c_coshf,
    c_sinh, c_sinhf, c_tanh, c_tanhf,

    -- * Exponential and logarithmic functions
    c_exp, c_expf, c_exp2, c_exp2f, c_expm1, c_expm1f, c_frexp, c_frexpf,
    c_ilogb, c_ilogbf, c_ldexp, c_ldexpf, c_log, c_logf, c_log10, c_log10f,
    c_log1p, c_log1pf, c_log2, c_log2f, c_logb, c_logbf, c_modf, c_modff,
    c_scalbn, c_scalbnf, c_scalbln, c_scalblnf,

    -- * Power and absolute-value functions
    c_cbrt, c_cbrtf, c_fabs, c_fabsf, c_hypot, c_hypotf, c_pow, c_powf, c_sqrt,
    c_sqrtf,

    -- * Remainder functions
    c_fmod, c_fmodf, c_remainder, c_remainderf, c_remquo, c_remquof,

    -- * Manipulation functions
    c_copysign, c_copysignf, c_nan, c_nanf, c_nextafter, c_nextafterf,

    -- * Error and gamma functions
    c_erf, c_erff, c_erfc, c_erfcf, c_lgamma, c_lgammaf, c_tgamma, c_tgammaf,

    -- * Nearest integer functions
    c_ceil, c_ceilf, c_floor, c_floorf, c_nearbyint, c_nearbyintf, c_rint,
    c_rintf, c_lrint, c_lrintf, c_llrint, c_llrintf, c_round, c_roundf,
    c_lround, c_lroundf, c_llround, c_llroundf, c_trunc, c_truncf,

    -- * Maximum, minimum, and positive difference functions
    c_fdim, c_fdimf, c_fmax, c_fmaxf, c_fmin, c_fminf,

    -- * Floating multiply-add
    c_fma, c_fmaf,

    -- * Haskell wrappers
    libmDouble, libmFloat, libmDouble2, libmFloat2, libmDouble3, libmFloat3
) where

import Prelude hiding (Double, Float)

import Data.Floating.Types
import Foreign
import Foreign.C

libmDouble :: (CDouble -> CDouble) -> Double -> Double
libmDouble f a = toFloating $ f (toFloating a)

libmFloat :: (CFloat -> CFloat) -> Float -> Float
libmFloat f a = toFloating $ f (toFloating a)

libmDouble2 :: (CDouble -> CDouble -> CDouble) -> Double -> Double -> Double
libmDouble2 f a b = toFloating $ f (toFloating a) (toFloating b)

libmFloat2 :: (CFloat -> CFloat -> CFloat) -> Float -> Float -> Float
libmFloat2 f a b = toFloating $ f (toFloating a) (toFloating b)

libmDouble3 :: (CDouble -> CDouble -> CDouble -> CDouble)
    -> Double -> Double -> Double -> Double
libmDouble3 f a b c = toFloating
    $ f (toFloating a) (toFloating b) (toFloating c)

libmFloat3 :: (CFloat -> CFloat -> CFloat -> CFloat)
    -> Float -> Float -> Float -> Float
libmFloat3 f a b c = toFloating
    $ f (toFloating a) (toFloating b) (toFloating c)

-- 7.12.4 Trigonometric functions
foreign import ccall unsafe "acos"
    c_acos :: CDouble -> CDouble
foreign import ccall unsafe "acosf"
    c_acosf :: CFloat -> CFloat
foreign import ccall unsafe "asin"
    c_asin :: CDouble -> CDouble
foreign import ccall unsafe "asinf"
    c_asinf :: CFloat -> CFloat
foreign import ccall unsafe "atan"
    c_atan :: CDouble -> CDouble
foreign import ccall unsafe "atanf"
    c_atanf :: CFloat -> CFloat
foreign import ccall unsafe "atan2"
    c_atan2 :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "atan2f"
    c_atan2f :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "cos"
    c_cos :: CDouble -> CDouble
foreign import ccall unsafe "cosf"
    c_cosf :: CFloat -> CFloat
foreign import ccall unsafe "sin"
    c_sin :: CDouble -> CDouble
foreign import ccall unsafe "sinf"
    c_sinf :: CFloat -> CFloat
foreign import ccall unsafe "tan"
    c_tan :: CDouble -> CDouble
foreign import ccall unsafe "tanf"
    c_tanf :: CFloat -> CFloat

-- 7.12.5 Hyperbolic functions
foreign import ccall unsafe "acosh"
    c_acosh :: CDouble -> CDouble
foreign import ccall unsafe "acoshf"
    c_acoshf :: CFloat -> CFloat
foreign import ccall unsafe "asinh"
    c_asinh :: CDouble -> CDouble
foreign import ccall unsafe "asinhf"
    c_asinhf :: CFloat -> CFloat
foreign import ccall unsafe "atanh"
    c_atanh :: CDouble -> CDouble
foreign import ccall unsafe "atanhf"
    c_atanhf :: CFloat -> CFloat
foreign import ccall unsafe "cosh"
    c_cosh :: CDouble -> CDouble
foreign import ccall unsafe "coshf"
    c_coshf :: CFloat -> CFloat
foreign import ccall unsafe "sinh"
    c_sinh :: CDouble -> CDouble
foreign import ccall unsafe "sinhf"
    c_sinhf :: CFloat -> CFloat
foreign import ccall unsafe "tanh"
    c_tanh :: CDouble -> CDouble
foreign import ccall unsafe "tanhf"
    c_tanhf :: CFloat -> CFloat

-- 7.12.6 Exponential and logarithmic functions
foreign import ccall unsafe "exp"
    c_exp :: CDouble -> CDouble
foreign import ccall unsafe "expf"
    c_expf :: CFloat -> CFloat
foreign import ccall unsafe "exp2"
    c_exp2 :: CDouble -> CDouble
foreign import ccall unsafe "exp2f"
    c_exp2f :: CFloat -> CFloat
foreign import ccall unsafe "expm1"
    c_expm1 :: CDouble -> CDouble
foreign import ccall unsafe "expm1f"
    c_expm1f :: CFloat -> CFloat
foreign import ccall unsafe "frexp"
    c_frexp :: CDouble -> Ptr CInt -> IO CDouble
foreign import ccall unsafe "frexpf"
    c_frexpf :: CFloat -> Ptr CInt -> IO CFloat
foreign import ccall unsafe "ilogb"
    c_ilogb :: CDouble -> CInt
foreign import ccall unsafe "ilogbf"
    c_ilogbf :: CFloat -> CInt
foreign import ccall unsafe "ldexp"
    c_ldexp :: CDouble -> CInt -> CDouble
foreign import ccall unsafe "ldexpf"
    c_ldexpf :: CFloat -> CInt -> CFloat
foreign import ccall unsafe "log"
    c_log :: CDouble -> CDouble
foreign import ccall unsafe "logf"
    c_logf :: CFloat -> CFloat
foreign import ccall unsafe "log10"
    c_log10 :: CDouble -> CDouble
foreign import ccall unsafe "log10f"
    c_log10f :: CFloat -> CFloat
foreign import ccall unsafe "log1p"
    c_log1p :: CDouble -> CDouble
foreign import ccall unsafe "log1pf"
    c_log1pf :: CFloat -> CFloat
foreign import ccall unsafe "log2"
    c_log2 :: CDouble -> CDouble
foreign import ccall unsafe "log2f"
    c_log2f :: CFloat -> CFloat
foreign import ccall unsafe "logb"
    c_logb :: CDouble -> CDouble
foreign import ccall unsafe "logbf"
    c_logbf :: CFloat -> CFloat
foreign import ccall unsafe "modf"
    c_modf :: CDouble -> Ptr CDouble -> IO CDouble
foreign import ccall unsafe "modff"
    c_modff :: CFloat -> Ptr CFloat -> IO CFloat
foreign import ccall unsafe "scalbn"
    c_scalbn :: CDouble -> CInt -> CDouble
foreign import ccall unsafe "scalbnf"
    c_scalbnf :: CFloat -> CInt -> CFloat
foreign import ccall unsafe "scalbln"
    c_scalbln :: CDouble -> CLong -> CDouble
foreign import ccall unsafe "scalblnf"
    c_scalblnf :: CFloat -> CLong -> CFloat

-- 7.12.7 Power and absolute-value functions
foreign import ccall unsafe "cbrt"
    c_cbrt :: CDouble -> CDouble
foreign import ccall unsafe "cbrtf"
    c_cbrtf :: CFloat -> CFloat
foreign import ccall unsafe "fabs"
    c_fabs :: CDouble -> CDouble
foreign import ccall unsafe "fabsf"
    c_fabsf :: CFloat -> CFloat
foreign import ccall unsafe "hypot"
    c_hypot :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "hypotf"
    c_hypotf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "pow"
    c_pow :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "powf"
    c_powf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "sqrt"
    c_sqrt :: CDouble -> CDouble
foreign import ccall unsafe "sqrtf"
    c_sqrtf :: CFloat -> CFloat

-- 7.12.8 Error and gamma functions
foreign import ccall unsafe "erf"
    c_erf :: CDouble -> CDouble
foreign import ccall unsafe "erff"
    c_erff :: CFloat -> CFloat
foreign import ccall unsafe "erfc"
    c_erfc :: CDouble -> CDouble
foreign import ccall unsafe "erfcf"
    c_erfcf :: CFloat -> CFloat
foreign import ccall unsafe "lgamma"
    c_lgamma :: CDouble -> CDouble
foreign import ccall unsafe "lgammaf"
    c_lgammaf :: CFloat -> CFloat
foreign import ccall unsafe "tgamma"
    c_tgamma :: CDouble -> CDouble
foreign import ccall unsafe "tgammaf"
    c_tgammaf :: CFloat -> CFloat

-- 7.12.9 Nearest integer functions
foreign import ccall unsafe "ceil"
    c_ceil :: CDouble -> CDouble
foreign import ccall unsafe "ceilf"
    c_ceilf :: CFloat -> CFloat
foreign import ccall unsafe "floor"
    c_floor :: CDouble -> CDouble
foreign import ccall unsafe "floorf"
    c_floorf :: CFloat -> CFloat
foreign import ccall unsafe "nearbyint"
    c_nearbyint :: CDouble -> CDouble
foreign import ccall unsafe "nearbyintf"
    c_nearbyintf :: CFloat -> CFloat
foreign import ccall unsafe "rint"
    c_rint :: CDouble -> CDouble
foreign import ccall unsafe "rintf"
    c_rintf :: CFloat -> CFloat
foreign import ccall unsafe "lrint"
    c_lrint :: CDouble -> CLong
foreign import ccall unsafe "lrintf"
    c_lrintf :: CFloat -> CLong
foreign import ccall unsafe "llrint"
    c_llrint :: CDouble -> CLLong
foreign import ccall unsafe "llrintf"
    c_llrintf :: CFloat -> CLLong
foreign import ccall unsafe "round"
    c_round :: CDouble -> CDouble
foreign import ccall unsafe "roundf"
    c_roundf :: CFloat -> CFloat
foreign import ccall unsafe "lround"
    c_lround :: CDouble -> CLong
foreign import ccall unsafe "lroundf"
    c_lroundf :: CFloat -> CLong
foreign import ccall unsafe "llround"
    c_llround :: CDouble -> CLLong
foreign import ccall unsafe "llroundf"
    c_llroundf :: CFloat -> CLLong
foreign import ccall unsafe "trunc"
    c_trunc :: CDouble -> CDouble
foreign import ccall unsafe "truncf"
    c_truncf :: CFloat -> CFloat

-- 7.12.10 Remainder functions
foreign import ccall unsafe "fmod"
    c_fmod :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "fmodf"
    c_fmodf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "remainder"
    c_remainder :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "remainderf"
    c_remainderf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "remquo"
    c_remquo :: CDouble -> CDouble -> Ptr CInt -> IO CDouble
foreign import ccall unsafe "remquof"
    c_remquof :: CFloat -> CFloat -> Ptr CInt -> IO CFloat

-- 7.12.11 Manipulation functions
foreign import ccall unsafe "copysign"
    c_copysign :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "copysignf"
    c_copysignf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "nan"
    c_nan :: CString -> IO CDouble
foreign import ccall unsafe "nanf"
    c_nanf :: CString -> IO CFloat
foreign import ccall unsafe "nextafter"
    c_nextafter :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "nextafterf"
    c_nextafterf :: CFloat -> CFloat -> CFloat
-- no nexttoward until we have a long double type.

-- 7.12.12 Maximum, minimum, and positive difference functions
foreign import ccall unsafe "fdim"
    c_fdim :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "fdimf"
    c_fdimf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "fmax"
    c_fmax :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "fmaxf"
    c_fmaxf :: CFloat -> CFloat -> CFloat
foreign import ccall unsafe "fmin"
    c_fmin :: CDouble -> CDouble -> CDouble
foreign import ccall unsafe "fminf"
    c_fminf :: CFloat -> CFloat -> CFloat

-- 7.12.13 Floating multiply-add
foreign import ccall unsafe "fma"
    c_fma :: CDouble -> CDouble -> CDouble -> CDouble
foreign import ccall unsafe "fmaf"
    c_fmaf :: CFloat -> CFloat -> CFloat -> CFloat