/*  actuar: Actuarial Functions and Heavy Tailed Distributions
 *
 *  Utilities for `dpq' handling (density/probability/quantile)
 *
 *  These (except ACT_DLIM__0) are copied from src/nmath/dpq.h of R
 *  sources with the names changed from "R_" to "ACT_".
 *
 *  AUTHOR: Vincent Goulet <vincent.goulet@act.ulaval.ca>
 *          with much indirect help from the R Core Team
 */

/* give_log in "d" & "mgf";  log_p in "p" & "q" : */
#define give_log log_p

#define ACT_D__0  (log_p ? R_NegInf : 0.)
#define ACT_D__1  (log_p ? 0. : 1.)
#define ACT_DT_0  (lower_tail ? ACT_D__0 : ACT_D__1)
#define ACT_DT_1  (lower_tail ? ACT_D__1 : ACT_D__0)

/* limiting cases in qzm */
#define ACT_Q_p0lim(p0)  ((p0 == 0) ? 1.0 : 0.0)

/* Use 0.5 - p + 0.5 to perhaps gain 1 bit of accuracy */
#define ACT_D_Lval(p)     (lower_tail ? (p) : (0.5 - (p) + 0.5))  /*  p  */
#define ACT_D_Cval(p)     (lower_tail ? (0.5 - (p) + 0.5) : (p))  /*  1 - p */

#define ACT_D_val(x)      (log_p  ? log(x) : (x))         /*  x  in pF(x,..) */
#define ACT_D_qIv(p)      (log_p  ? exp(p) : (p))         /*  p  in qF(p,..) */
#define ACT_DT_qIv(p)	  (log_p ? (lower_tail ? exp(p) : - expm1(p)) \
			       : ACT_D_Lval(p))   	  /*  1 - p  in qF(p,..) */
#define ACT_DT_1mqIv(p)	  (log_p ? (lower_tail ? - expm1(p) : exp(p)) \
			       : ACT_D_Cval(p))   	  /*  1 - p  in qF(p,..) */
#define ACT_D_exp(x)      (log_p  ?  (x)   : exp(x))      /* exp(x) */
#define ACT_D_Cexp(x)     (log_p  ? log(-expm1(x)) : (-expm1(x)))    /* [log](1-exp(x)) */
#define ACT_D_Clog(p)     (log_p  ? log1p(-(p)) : (0.5 - (p) + 0.5)) /* [log](1-p) */

#define ACT_DT_val(x)     (lower_tail ? ACT_D_val(x)  : ACT_D_Clog(x))
#define ACT_DT_Eval(x)    (lower_tail ? ACT_D_exp(x)  : ACT_D_Cexp(x))
#define ACT_DT_Cval(x)    (lower_tail ? ACT_D_Clog(x) : ACT_D_val(x))
#define ACT_DT_CEval(x)   (lower_tail ? ACT_D_Cexp(x) : ACT_D_exp(x))

/* Check value of p for discrete q<dist>(p, ...) */
#define ACT_Q_P01_check(p)			\
    if ((log_p	&& p > 0) ||			\
	(!log_p && (p < 0 || p > 1)) )		\
	return R_NaN

/* Check boundaries exactly for q<dist>(p, ...) functions.
 *
 * ACT_Q_P01_boundaries(p, _LEFT_, _RIGHT_) <==>
 *
 *     ACT_Q_P01_check(p);
 *     if (p == ACT_DT_0) return _LEFT_ ;
 *     if (p == ACT_DT_1) return _RIGHT_;
 *
 * just more efficient(fewer tests). Used only for continuous
 * distributions; for discrete distributions we need additionnal
 * checks immediately after R_Q_P01_check.
 */
#define ACT_Q_P01_boundaries(p, _LEFT_, _RIGHT_)	\
    if (log_p) {                                        \
        if(p > 0)                                       \
            return R_NaN;				\
        if(p == 0) /* upper bound*/                     \
            return lower_tail ? _RIGHT_ : _LEFT_;       \
        if(p == R_NegInf)                               \
            return lower_tail ? _LEFT_ : _RIGHT_;       \
    }                                                   \
    else { /* !log_p */                                 \
        if(p < 0 || p > 1)                              \
            return R_NaN;				\
        if(p == 0)                                      \
            return lower_tail ? _LEFT_ : _RIGHT_;       \
        if(p == 1)                                      \
            return lower_tail ? _RIGHT_ : _LEFT_;       \
    }

/* Infinite limit in lev<dist(...) */
#define ACT_DLIM__0(x, y)   (R_FINITE(x) ? R_pow(x, y) : 0.)

/* This is taken from src/nmath/nmath.h of R sources */
#ifdef HAVE_NEARYINT
# define ACT_forceint(x)   nearbyint()
#else
# define ACT_forceint(x)   round(x)
#endif
# define ACT_nonint(x) 	  (fabs((x) - ACT_forceint(x)) > 1e-7*fmax2(1., fabs(x)))

/* Check for non-integer x in discrete d<distr>(x, ...) */
#define ACT_D_nonint_check(x)					\
    if (ACT_nonint(x)) {					\
	warning(_("non-integer x = %f"), x);			\
	return ACT_D__0;					\
    }
