static int mpfr_all_div (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t r) { mpfr_t a2; unsigned int oldflags, newflags; int inex, inex2; oldflags = __gmpfr_flags; inex = mpfr_div (a, b, c, r); if (a == b || a == c) return inex; newflags = __gmpfr_flags; mpfr_init2 (a2, MPFR_PREC (a)); if (mpfr_integer_p (b) && ! (MPFR_IS_ZERO (b) && MPFR_IS_NEG (b))) { /* b is an integer, but not -0 (-0 is rejected as it becomes +0 when converted to an integer). */ if (mpfr_fits_ulong_p (b, MPFR_RNDA)) { __gmpfr_flags = oldflags; inex2 = mpfr_ui_div (a2, mpfr_get_ui (b, MPFR_RNDN), c, r); MPFR_ASSERTN (SAME_SIGN (inex2, inex)); MPFR_ASSERTN (__gmpfr_flags == newflags); check_equal (a, a2, "mpfr_ui_div", b, c, r); } if (mpfr_fits_slong_p (b, MPFR_RNDA)) { __gmpfr_flags = oldflags; inex2 = mpfr_si_div (a2, mpfr_get_si (b, MPFR_RNDN), c, r); MPFR_ASSERTN (SAME_SIGN (inex2, inex)); MPFR_ASSERTN (__gmpfr_flags == newflags); check_equal (a, a2, "mpfr_si_div", b, c, r); } } if (mpfr_integer_p (c) && ! (MPFR_IS_ZERO (c) && MPFR_IS_NEG (c))) { /* c is an integer, but not -0 (-0 is rejected as it becomes +0 when converted to an integer). */ if (mpfr_fits_ulong_p (c, MPFR_RNDA)) { __gmpfr_flags = oldflags; inex2 = mpfr_div_ui (a2, b, mpfr_get_ui (c, MPFR_RNDN), r); MPFR_ASSERTN (SAME_SIGN (inex2, inex)); MPFR_ASSERTN (__gmpfr_flags == newflags); check_equal (a, a2, "mpfr_div_ui", b, c, r); } if (mpfr_fits_slong_p (c, MPFR_RNDA)) { __gmpfr_flags = oldflags; inex2 = mpfr_div_si (a2, b, mpfr_get_si (c, MPFR_RNDN), r); MPFR_ASSERTN (SAME_SIGN (inex2, inex)); MPFR_ASSERTN (__gmpfr_flags == newflags); check_equal (a, a2, "mpfr_div_si", b, c, r); } } mpfr_clear (a2); return inex; }
/* We use the reflection formula Gamma(1+t) Gamma(1-t) = - Pi t / sin(Pi (1 + t)) in order to treat the case x <= 1, i.e. with x = 1-t, then Gamma(x) = -Pi*(1-x)/sin(Pi*(2-x))/GAMMA(2-x) */ int mpfr_gamma (mpfr_ptr gamma, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_t xp, GammaTrial, tmp, tmp2; mpz_t fact; mpfr_prec_t realprec; int compared, is_integer; int inex = 0; /* 0 means: result gamma not set yet */ MPFR_GROUP_DECL (group); MPFR_SAVE_EXPO_DECL (expo); MPFR_ZIV_DECL (loop); MPFR_LOG_FUNC (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode), ("gamma[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (gamma), mpfr_log_prec, gamma, inex)); /* Trivial cases */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { if (MPFR_IS_NAN (x)) { MPFR_SET_NAN (gamma); MPFR_RET_NAN; } else if (MPFR_IS_INF (x)) { if (MPFR_IS_NEG (x)) { MPFR_SET_NAN (gamma); MPFR_RET_NAN; } else { MPFR_SET_INF (gamma); MPFR_SET_POS (gamma); MPFR_RET (0); /* exact */ } } else /* x is zero */ { MPFR_ASSERTD(MPFR_IS_ZERO(x)); MPFR_SET_INF(gamma); MPFR_SET_SAME_SIGN(gamma, x); MPFR_SET_DIVBY0 (); MPFR_RET (0); /* exact */ } } /* Check for tiny arguments, where gamma(x) ~ 1/x - euler + .... We know from "Bound on Runs of Zeros and Ones for Algebraic Functions", Proceedings of Arith15, T. Lang and J.-M. Muller, 2001, that the maximal number of consecutive zeroes or ones after the round bit is n-1 for an input of n bits. But we need a more precise lower bound. Assume x has n bits, and 1/x is near a floating-point number y of n+1 bits. We can write x = X*2^e, y = Y/2^f with X, Y integers of n and n+1 bits. Thus X*Y^2^(e-f) is near from 1, i.e., X*Y is near from 2^(f-e). Two cases can happen: (i) either X*Y is exactly 2^(f-e), but this can happen only if X and Y are themselves powers of two, i.e., x is a power of two; (ii) or X*Y is at distance at least one from 2^(f-e), thus |xy-1| >= 2^(e-f), or |y-1/x| >= 2^(e-f)/x = 2^(-f)/X >= 2^(-f-n). Since ufp(y) = 2^(n-f) [ufp = unit in first place], this means that the distance |y-1/x| >= 2^(-2n) ufp(y). Now assuming |gamma(x)-1/x| <= 1, which is true for x <= 1, if 2^(-2n) ufp(y) >= 2, the error is at most 2^(-2n-1) ufp(y), and round(1/x) with precision >= 2n+2 gives the correct result. If x < 2^E, then y > 2^(-E), thus ufp(y) > 2^(-E-1). A sufficient condition is thus EXP(x) + 2 <= -2 MAX(PREC(x),PREC(Y)). */ if (MPFR_GET_EXP (x) + 2 <= -2 * (mpfr_exp_t) MAX(MPFR_PREC(x), MPFR_PREC(gamma))) { int sign = MPFR_SIGN (x); /* retrieve sign before possible override */ int special; MPFR_BLOCK_DECL (flags); MPFR_SAVE_EXPO_MARK (expo); /* for overflow cases, see below; this needs to be done before x possibly gets overridden. */ special = MPFR_GET_EXP (x) == 1 - MPFR_EMAX_MAX && MPFR_IS_POS_SIGN (sign) && MPFR_IS_LIKE_RNDD (rnd_mode, sign) && mpfr_powerof2_raw (x); MPFR_BLOCK (flags, inex = mpfr_ui_div (gamma, 1, x, rnd_mode)); if (inex == 0) /* x is a power of two */ { /* return RND(1/x - euler) = RND(+/- 2^k - eps) with eps > 0 */ if (rnd_mode == MPFR_RNDN || MPFR_IS_LIKE_RNDU (rnd_mode, sign)) inex = 1; else { mpfr_nextbelow (gamma); inex = -1; } } else if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags))) { /* Overflow in the division 1/x. This is a real overflow, except in RNDZ or RNDD when 1/x = 2^emax, i.e. x = 2^(-emax): due to the "- euler", the rounded value in unbounded exponent range is 0.111...11 * 2^emax (not an overflow). */ if (!special) MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, flags); } MPFR_SAVE_EXPO_FREE (expo); /* Note: an overflow is possible with an infinite result; in this case, the overflow flag will automatically be restored by mpfr_check_range. */ return mpfr_check_range (gamma, inex, rnd_mode); } is_integer = mpfr_integer_p (x); /* gamma(x) for x a negative integer gives NaN */ if (is_integer && MPFR_IS_NEG(x)) { MPFR_SET_NAN (gamma); MPFR_RET_NAN; } compared = mpfr_cmp_ui (x, 1); if (compared == 0) return mpfr_set_ui (gamma, 1, rnd_mode); /* if x is an integer that fits into an unsigned long, use mpfr_fac_ui if argument is not too large. If precision is p, fac_ui costs O(u*p), whereas gamma costs O(p*M(p)), so for u <= M(p), fac_ui should be faster. We approximate here M(p) by p*log(p)^2, which is not a bad guess. Warning: since the generic code does not handle exact cases, we want all cases where gamma(x) is exact to be treated here. */ if (is_integer && mpfr_fits_ulong_p (x, MPFR_RNDN)) { unsigned long int u; mpfr_prec_t p = MPFR_PREC(gamma); u = mpfr_get_ui (x, MPFR_RNDN); if (u < 44787929UL && bits_fac (u - 1) <= p + (rnd_mode == MPFR_RNDN)) /* bits_fac: lower bound on the number of bits of m, where gamma(x) = (u-1)! = m*2^e with m odd. */ return mpfr_fac_ui (gamma, u - 1, rnd_mode); /* if bits_fac(...) > p (resp. p+1 for rounding to nearest), then gamma(x) cannot be exact in precision p (resp. p+1). FIXME: remove the test u < 44787929UL after changing bits_fac to return a mpz_t or mpfr_t. */ } MPFR_SAVE_EXPO_MARK (expo); /* check for overflow: according to (6.1.37) in Abramowitz & Stegun, gamma(x) >= exp(-x) * x^(x-1/2) * sqrt(2*Pi) >= 2 * (x/e)^x / x for x >= 1 */ if (compared > 0) { mpfr_t yp; mpfr_exp_t expxp; MPFR_BLOCK_DECL (flags); /* quick test for the default exponent range */ if (mpfr_get_emax () >= 1073741823UL && MPFR_GET_EXP(x) <= 25) { MPFR_SAVE_EXPO_FREE (expo); return mpfr_gamma_aux (gamma, x, rnd_mode); } /* 1/e rounded down to 53 bits */ #define EXPM1_STR "0.010111100010110101011000110110001011001110111100111" mpfr_init2 (xp, 53); mpfr_init2 (yp, 53); mpfr_set_str_binary (xp, EXPM1_STR); mpfr_mul (xp, x, xp, MPFR_RNDZ); mpfr_sub_ui (yp, x, 2, MPFR_RNDZ); mpfr_pow (xp, xp, yp, MPFR_RNDZ); /* (x/e)^(x-2) */ mpfr_set_str_binary (yp, EXPM1_STR); mpfr_mul (xp, xp, yp, MPFR_RNDZ); /* x^(x-2) / e^(x-1) */ mpfr_mul (xp, xp, yp, MPFR_RNDZ); /* x^(x-2) / e^x */ mpfr_mul (xp, xp, x, MPFR_RNDZ); /* lower bound on x^(x-1) / e^x */ MPFR_BLOCK (flags, mpfr_mul_2ui (xp, xp, 1, MPFR_RNDZ)); expxp = MPFR_GET_EXP (xp); mpfr_clear (xp); mpfr_clear (yp); MPFR_SAVE_EXPO_FREE (expo); return MPFR_OVERFLOW (flags) || expxp > __gmpfr_emax ? mpfr_overflow (gamma, rnd_mode, 1) : mpfr_gamma_aux (gamma, x, rnd_mode); } /* now compared < 0 */ /* check for underflow: for x < 1, gamma(x) = Pi*(x-1)/sin(Pi*(2-x))/gamma(2-x). Since gamma(2-x) >= 2 * ((2-x)/e)^(2-x) / (2-x), we have |gamma(x)| <= Pi*(1-x)*(2-x)/2/((2-x)/e)^(2-x) / |sin(Pi*(2-x))| <= 12 * ((2-x)/e)^x / |sin(Pi*(2-x))|. To avoid an underflow in ((2-x)/e)^x, we compute the logarithm. */ if (MPFR_IS_NEG(x)) { int underflow = 0, sgn, ck; mpfr_prec_t w; mpfr_init2 (xp, 53); mpfr_init2 (tmp, 53); mpfr_init2 (tmp2, 53); /* we want an upper bound for x * [log(2-x)-1]. since x < 0, we need a lower bound on log(2-x) */ mpfr_ui_sub (xp, 2, x, MPFR_RNDD); mpfr_log (xp, xp, MPFR_RNDD); mpfr_sub_ui (xp, xp, 1, MPFR_RNDD); mpfr_mul (xp, xp, x, MPFR_RNDU); /* we need an upper bound on 1/|sin(Pi*(2-x))|, thus a lower bound on |sin(Pi*(2-x))|. If 2-x is exact, then the error of Pi*(2-x) is (1+u)^2 with u = 2^(-p) thus the error on sin(Pi*(2-x)) is less than 1/2ulp + 3Pi(2-x)u, assuming u <= 1, thus <= u + 3Pi(2-x)u */ w = mpfr_gamma_2_minus_x_exact (x); /* 2-x is exact for prec >= w */ w += 17; /* to get tmp2 small enough */ mpfr_set_prec (tmp, w); mpfr_set_prec (tmp2, w); MPFR_DBGRES (ck = mpfr_ui_sub (tmp, 2, x, MPFR_RNDN)); MPFR_ASSERTD (ck == 0); /* tmp = 2-x exactly */ mpfr_const_pi (tmp2, MPFR_RNDN); mpfr_mul (tmp2, tmp2, tmp, MPFR_RNDN); /* Pi*(2-x) */ mpfr_sin (tmp, tmp2, MPFR_RNDN); /* sin(Pi*(2-x)) */ sgn = mpfr_sgn (tmp); mpfr_abs (tmp, tmp, MPFR_RNDN); mpfr_mul_ui (tmp2, tmp2, 3, MPFR_RNDU); /* 3Pi(2-x) */ mpfr_add_ui (tmp2, tmp2, 1, MPFR_RNDU); /* 3Pi(2-x)+1 */ mpfr_div_2ui (tmp2, tmp2, mpfr_get_prec (tmp), MPFR_RNDU); /* if tmp2<|tmp|, we get a lower bound */ if (mpfr_cmp (tmp2, tmp) < 0) { mpfr_sub (tmp, tmp, tmp2, MPFR_RNDZ); /* low bnd on |sin(Pi*(2-x))| */ mpfr_ui_div (tmp, 12, tmp, MPFR_RNDU); /* upper bound */ mpfr_log2 (tmp, tmp, MPFR_RNDU); mpfr_add (xp, tmp, xp, MPFR_RNDU); /* The assert below checks that expo.saved_emin - 2 always fits in a long. FIXME if we want to allow mpfr_exp_t to be a long long, for instance. */ MPFR_ASSERTN (MPFR_EMIN_MIN - 2 >= LONG_MIN); underflow = mpfr_cmp_si (xp, expo.saved_emin - 2) <= 0; } mpfr_clear (xp); mpfr_clear (tmp); mpfr_clear (tmp2); if (underflow) /* the sign is the opposite of that of sin(Pi*(2-x)) */ { MPFR_SAVE_EXPO_FREE (expo); return mpfr_underflow (gamma, (rnd_mode == MPFR_RNDN) ? MPFR_RNDZ : rnd_mode, -sgn); } } realprec = MPFR_PREC (gamma); /* we want both 1-x and 2-x to be exact */ { mpfr_prec_t w; w = mpfr_gamma_1_minus_x_exact (x); if (realprec < w) realprec = w; w = mpfr_gamma_2_minus_x_exact (x); if (realprec < w) realprec = w; } realprec = realprec + MPFR_INT_CEIL_LOG2 (realprec) + 20; MPFR_ASSERTD(realprec >= 5); MPFR_GROUP_INIT_4 (group, realprec + MPFR_INT_CEIL_LOG2 (realprec) + 20, xp, tmp, tmp2, GammaTrial); mpz_init (fact); MPFR_ZIV_INIT (loop, realprec); for (;;) { mpfr_exp_t err_g; int ck; MPFR_GROUP_REPREC_4 (group, realprec, xp, tmp, tmp2, GammaTrial); /* reflection formula: gamma(x) = Pi*(x-1)/sin(Pi*(2-x))/gamma(2-x) */ ck = mpfr_ui_sub (xp, 2, x, MPFR_RNDN); /* 2-x, exact */ MPFR_ASSERTD(ck == 0); (void) ck; /* use ck to avoid a warning */ mpfr_gamma (tmp, xp, MPFR_RNDN); /* gamma(2-x), error (1+u) */ mpfr_const_pi (tmp2, MPFR_RNDN); /* Pi, error (1+u) */ mpfr_mul (GammaTrial, tmp2, xp, MPFR_RNDN); /* Pi*(2-x), error (1+u)^2 */ err_g = MPFR_GET_EXP(GammaTrial); mpfr_sin (GammaTrial, GammaTrial, MPFR_RNDN); /* sin(Pi*(2-x)) */ /* If tmp is +Inf, we compute exp(lngamma(x)). */ if (mpfr_inf_p (tmp)) { inex = mpfr_explgamma (gamma, x, &expo, tmp, tmp2, rnd_mode); if (inex) goto end; else goto ziv_next; } err_g = err_g + 1 - MPFR_GET_EXP(GammaTrial); /* let g0 the true value of Pi*(2-x), g the computed value. We have g = g0 + h with |h| <= |(1+u^2)-1|*g. Thus sin(g) = sin(g0) + h' with |h'| <= |(1+u^2)-1|*g. The relative error is thus bounded by |(1+u^2)-1|*g/sin(g) <= |(1+u^2)-1|*2^err_g. <= 2.25*u*2^err_g for |u|<=1/4. With the rounding error, this gives (0.5 + 2.25*2^err_g)*u. */ ck = mpfr_sub_ui (xp, x, 1, MPFR_RNDN); /* x-1, exact */ MPFR_ASSERTD(ck == 0); (void) ck; /* use ck to avoid a warning */ mpfr_mul (xp, tmp2, xp, MPFR_RNDN); /* Pi*(x-1), error (1+u)^2 */ mpfr_mul (GammaTrial, GammaTrial, tmp, MPFR_RNDN); /* [1 + (0.5 + 2.25*2^err_g)*u]*(1+u)^2 = 1 + (2.5 + 2.25*2^err_g)*u + (0.5 + 2.25*2^err_g)*u*(2u+u^2) + u^2. For err_g <= realprec-2, we have (0.5 + 2.25*2^err_g)*u <= 0.5*u + 2.25/4 <= 0.6875 and u^2 <= u/4, thus (0.5 + 2.25*2^err_g)*u*(2u+u^2) + u^2 <= 0.6875*(2u+u/4) + u/4 <= 1.8*u, thus the rel. error is bounded by (4.5 + 2.25*2^err_g)*u. */ mpfr_div (GammaTrial, xp, GammaTrial, MPFR_RNDN); /* the error is of the form (1+u)^3/[1 + (4.5 + 2.25*2^err_g)*u]. For realprec >= 5 and err_g <= realprec-2, [(4.5 + 2.25*2^err_g)*u]^2 <= 0.71, and for |y|<=0.71, 1/(1-y) can be written 1+a*y with a<=4. (1+u)^3 * (1+4*(4.5 + 2.25*2^err_g)*u) = 1 + (21 + 9*2^err_g)*u + (57+27*2^err_g)*u^2 + (55+27*2^err_g)*u^3 + (18+9*2^err_g)*u^4 <= 1 + (21 + 9*2^err_g)*u + (57+27*2^err_g)*u^2 + (56+28*2^err_g)*u^3 <= 1 + (21 + 9*2^err_g)*u + (59+28*2^err_g)*u^2 <= 1 + (23 + 10*2^err_g)*u. The final error is thus bounded by (23 + 10*2^err_g) ulps, which is <= 2^6 for err_g<=2, and <= 2^(err_g+4) for err_g >= 2. */ err_g = (err_g <= 2) ? 6 : err_g + 4; if (MPFR_LIKELY (MPFR_CAN_ROUND (GammaTrial, realprec - err_g, MPFR_PREC(gamma), rnd_mode))) break; ziv_next: MPFR_ZIV_NEXT (loop, realprec); } end: MPFR_ZIV_FREE (loop); if (inex == 0) inex = mpfr_set (gamma, GammaTrial, rnd_mode); MPFR_GROUP_CLEAR (group); mpz_clear (fact); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (gamma, inex, rnd_mode); }
int main (void) { mpfr_t x, y; int i, r; tests_start_mpfr (); mpfr_init2 (x, 256); mpfr_init2 (y, 8); RND_LOOP (r) { /* Check NAN */ mpfr_set_nan (x); if (mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (1); if (mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (2); if (mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (3); if (mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (4); if (mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (5); if (mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (6); /* Check INF */ mpfr_set_inf (x, 1); if (mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (7); if (mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (8); if (mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (9); if (mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (10); if (mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (11); if (mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (12); /* Check Zero */ MPFR_SET_ZERO (x); if (!mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (13); if (!mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (14); if (!mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (15); if (!mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (16); if (!mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (17); if (!mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (18); /* Check small positive op */ mpfr_set_str1 (x, "1@-1"); if (!mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (19); if (!mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (20); if (!mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (21); if (!mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (22); if (!mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (23); if (!mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (24); /* Check 17 */ mpfr_set_ui (x, 17, MPFR_RNDN); if (!mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (25); if (!mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (26); if (!mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (27); if (!mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (28); if (!mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (29); if (!mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (30); /* Check all other values */ mpfr_set_ui (x, ULONG_MAX, MPFR_RNDN); mpfr_mul_2exp (x, x, 1, MPFR_RNDN); if (mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (31); if (mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (32); mpfr_mul_2exp (x, x, 40, MPFR_RNDN); if (mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (33); if (mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (34); if (mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (35); if (mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (36); if (mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (37); mpfr_set_ui (x, ULONG_MAX, MPFR_RNDN); if (!mpfr_fits_ulong_p (x, (mpfr_rnd_t) r)) ERROR1 (38); mpfr_set_ui (x, LONG_MAX, MPFR_RNDN); if (!mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (39); mpfr_set_ui (x, UINT_MAX, MPFR_RNDN); if (!mpfr_fits_uint_p (x, (mpfr_rnd_t) r)) ERROR1 (40); mpfr_set_ui (x, INT_MAX, MPFR_RNDN); if (!mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (41); mpfr_set_ui (x, USHRT_MAX, MPFR_RNDN); if (!mpfr_fits_ushort_p (x, (mpfr_rnd_t) r)) ERROR1 (42); mpfr_set_ui (x, SHRT_MAX, MPFR_RNDN); if (!mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (43); mpfr_set_si (x, 1, MPFR_RNDN); if (!mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (44); if (!mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (45); /* Check negative op */ for (i = 1; i <= 4; i++) { int inv; mpfr_set_si_2exp (x, -i, -2, MPFR_RNDN); mpfr_rint (y, x, (mpfr_rnd_t) r); inv = MPFR_NOTZERO (y); if (!mpfr_fits_ulong_p (x, (mpfr_rnd_t) r) ^ inv) ERROR1 (46); if (!mpfr_fits_slong_p (x, (mpfr_rnd_t) r)) ERROR1 (47); if (!mpfr_fits_uint_p (x, (mpfr_rnd_t) r) ^ inv) ERROR1 (48); if (!mpfr_fits_sint_p (x, (mpfr_rnd_t) r)) ERROR1 (49); if (!mpfr_fits_ushort_p (x, (mpfr_rnd_t) r) ^ inv) ERROR1 (50); if (!mpfr_fits_sshort_p (x, (mpfr_rnd_t) r)) ERROR1 (51); } } mpfr_clear (x); mpfr_clear (y); check_intmax (); tests_end_mpfr (); return 0; }
int main (void) { mpfr_t x; tests_start_mpfr (); mpfr_init2 (x, 256); /* Check NAN */ mpfr_set_nan(x); if (mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_slong_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_uint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_sint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR1; /* Check INF */ mpfr_set_inf(x, 1); if (mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_slong_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_uint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_sint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR1; /* Check Zero */ MPFR_SET_ZERO(x); if (!mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_slong_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_uint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR2; /* Check small op */ mpfr_set_str1 (x, "1@-1"); if (!mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_slong_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_uint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR2; /* Check 17 */ mpfr_set_ui (x, 17, GMP_RNDN); if (!mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_slong_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_uint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR2; /* Check all other values */ mpfr_set_ui(x, ULONG_MAX, GMP_RNDN); mpfr_mul_2exp(x, x, 1, GMP_RNDN); if (mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_slong_p(x, GMP_RNDN)) ERROR1; mpfr_mul_2exp(x, x, 40, GMP_RNDN); if (mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_uint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_sint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR1; mpfr_set_ui(x, ULONG_MAX, GMP_RNDN); if (!mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR2; mpfr_set_ui(x, LONG_MAX, GMP_RNDN); if (!mpfr_fits_slong_p(x, GMP_RNDN)) ERROR2; mpfr_set_ui(x, UINT_MAX, GMP_RNDN); if (!mpfr_fits_uint_p(x, GMP_RNDN)) ERROR2; mpfr_set_ui(x, INT_MAX, GMP_RNDN); if (!mpfr_fits_sint_p(x, GMP_RNDN)) ERROR2; mpfr_set_ui(x, USHRT_MAX, GMP_RNDN); if (!mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR2; mpfr_set_ui(x, SHRT_MAX, GMP_RNDN); if (!mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR2; mpfr_set_si(x, 1, GMP_RNDN); if (!mpfr_fits_sint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR2; /* Check negative value */ mpfr_set_si (x, -1, GMP_RNDN); if (!mpfr_fits_sint_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_sshort_p(x, GMP_RNDN)) ERROR2; if (!mpfr_fits_slong_p(x, GMP_RNDN)) ERROR2; if (mpfr_fits_uint_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_ushort_p(x, GMP_RNDN)) ERROR1; if (mpfr_fits_ulong_p(x, GMP_RNDN)) ERROR1; mpfr_clear (x); check_intmax (); tests_end_mpfr (); return 0; }
int mpfr_log10 (mpfr_ptr r, mpfr_srcptr a, mpfr_rnd_t rnd_mode) { int inexact; MPFR_SAVE_EXPO_DECL (expo); /* If a is NaN, the result is NaN */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (a))) { if (MPFR_IS_NAN (a)) { MPFR_SET_NAN (r); MPFR_RET_NAN; } /* check for infinity before zero */ else if (MPFR_IS_INF (a)) { if (MPFR_IS_NEG (a)) /* log10(-Inf) = NaN */ { MPFR_SET_NAN (r); MPFR_RET_NAN; } else /* log10(+Inf) = +Inf */ { MPFR_SET_INF (r); MPFR_SET_POS (r); MPFR_RET (0); /* exact */ } } else /* a = 0 */ { MPFR_ASSERTD (MPFR_IS_ZERO (a)); MPFR_SET_INF (r); MPFR_SET_NEG (r); MPFR_RET (0); /* log10(0) is an exact -infinity */ } } /* If a is negative, the result is NaN */ if (MPFR_UNLIKELY (MPFR_IS_NEG (a))) { MPFR_SET_NAN (r); MPFR_RET_NAN; } /* If a is 1, the result is 0 */ if (mpfr_cmp_ui (a, 1) == 0) { MPFR_SET_ZERO (r); MPFR_SET_POS (r); MPFR_RET (0); /* result is exact */ } MPFR_SAVE_EXPO_MARK (expo); /* General case */ { /* Declaration of the intermediary variable */ mpfr_t t, tt; MPFR_ZIV_DECL (loop); /* Declaration of the size variable */ mpfr_prec_t Ny = MPFR_PREC(r); /* Precision of output variable */ mpfr_prec_t Nt; /* Precision of the intermediary variable */ mpfr_exp_t err; /* Precision of error */ /* compute the precision of intermediary variable */ /* the optimal number of bits : see algorithms.tex */ Nt = Ny + 4 + MPFR_INT_CEIL_LOG2 (Ny); /* initialise of intermediary variables */ mpfr_init2 (t, Nt); mpfr_init2 (tt, Nt); /* First computation of log10 */ MPFR_ZIV_INIT (loop, Nt); for (;;) { /* compute log10 */ mpfr_set_ui (t, 10, MPFR_RNDN); /* 10 */ mpfr_log (t, t, MPFR_RNDD); /* log(10) */ mpfr_log (tt, a, MPFR_RNDN); /* log(a) */ mpfr_div (t, tt, t, MPFR_RNDN); /* log(a)/log(10) */ /* estimation of the error */ err = Nt - 4; if (MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode))) break; /* log10(10^n) is exact: FIXME: Can we have 10^n exactly representable as a mpfr_t but n can't fit an unsigned long? */ if (MPFR_IS_POS (t) && mpfr_integer_p (t) && mpfr_fits_ulong_p (t, MPFR_RNDN) && !mpfr_ui_pow_ui (tt, 10, mpfr_get_ui (t, MPFR_RNDN), MPFR_RNDN) && mpfr_cmp (a, tt) == 0) break; /* actualisation of the precision */ MPFR_ZIV_NEXT (loop, Nt); mpfr_set_prec (t, Nt); mpfr_set_prec (tt, Nt); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (r, t, rnd_mode); mpfr_clear (t); mpfr_clear (tt); } MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (r, inexact, rnd_mode); }
/* tgeneric(prec_min, prec_max, step, exp_max) checks rounding with random numbers: - with precision ranging from prec_min to prec_max with an increment of step, - with exponent between -exp_max and exp_max. It also checks parameter reuse (it is assumed here that either two mpc_t variables are equal or they are different, in the sense that the real part of one of them cannot be the imaginary part of the other). */ void tgeneric (mpc_function function, mpfr_prec_t prec_min, mpfr_prec_t prec_max, mpfr_prec_t step, mpfr_exp_t exp_max) { unsigned long ul1 = 0, ul2 = 0; long lo = 0; int i = 0; mpfr_t x1, x2, xxxx; mpc_t z1, z2, z3, z4, z5, zzzz, zzzz2; mpfr_rnd_t rnd_re, rnd_im, rnd2_re, rnd2_im; mpfr_prec_t prec; mpfr_exp_t exp_min; int special, special_cases; mpc_init2 (z1, prec_max); switch (function.type) { case C_CC: mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (z4, prec_max); mpc_init2 (zzzz, 4*prec_max); special_cases = 8; break; case CCCC: mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (z4, prec_max); mpc_init2 (z5, prec_max); mpc_init2 (zzzz, 4*prec_max); special_cases = 8; break; case FC: mpfr_init2 (x1, prec_max); mpfr_init2 (x2, prec_max); mpfr_init2 (xxxx, 4*prec_max); mpc_init2 (z2, prec_max); special_cases = 4; break; case CCF: case CFC: mpfr_init2 (x1, prec_max); mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (zzzz, 4*prec_max); special_cases = 6; break; case CCI: case CCS: case CCU: case CUC: mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (zzzz, 4*prec_max); special_cases = 5; break; case CUUC: mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (zzzz, 4*prec_max); special_cases = 6; break; case CC_C: mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (z4, prec_max); mpc_init2 (z5, prec_max); mpc_init2 (zzzz, 4*prec_max); mpc_init2 (zzzz2, 4*prec_max); special_cases = 4; break; case CC: default: mpc_init2 (z2, prec_max); mpc_init2 (z3, prec_max); mpc_init2 (zzzz, 4*prec_max); special_cases = 4; } exp_min = mpfr_get_emin (); if (exp_max <= 0 || exp_max > mpfr_get_emax ()) exp_max = mpfr_get_emax(); if (-exp_max > exp_min) exp_min = - exp_max; if (step < 1) step = 1; for (prec = prec_min, special = 0; prec <= prec_max || special <= special_cases; prec+=step, special += (prec > prec_max ? 1 : 0)) { /* In the end, test functions in special cases of purely real, purely imaginary or infinite arguments. */ /* probability of one zero part in 256th (25 is almost 10%) */ const unsigned int zero_probability = special != 0 ? 0 : 25; mpc_set_prec (z1, prec); test_default_random (z1, exp_min, exp_max, 128, zero_probability); switch (function.type) { case C_CC: mpc_set_prec (z2, prec); test_default_random (z2, exp_min, exp_max, 128, zero_probability); mpc_set_prec (z3, prec); mpc_set_prec (z4, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: mpfr_set_ui (mpc_realref (z2), 0, MPFR_RNDN); break; case 6: mpfr_set_inf (mpc_realref (z2), -1); break; case 7: mpfr_set_ui (mpc_imagref (z2), 0, MPFR_RNDN); break; case 8: mpfr_set_inf (mpc_imagref (z2), +1); break; } break; case CCCC: mpc_set_prec (z2, prec); test_default_random (z2, exp_min, exp_max, 128, zero_probability); mpc_set_prec (z3, prec); mpc_set_prec (z4, prec); mpc_set_prec (z5, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: mpfr_set_ui (mpc_realref (z2), 0, MPFR_RNDN); break; case 6: mpfr_set_inf (mpc_realref (z2), -1); break; case 7: mpfr_set_ui (mpc_imagref (z2), 0, MPFR_RNDN); break; case 8: mpfr_set_inf (mpc_imagref (z2), +1); break; } break; case FC: mpc_set_prec (z2, prec); mpfr_set_prec (x1, prec); mpfr_set_prec (x2, prec); mpfr_set_prec (xxxx, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; } break; case CCU: case CUC: mpc_set_prec (z2, 128); do { test_default_random (z2, 0, 64, 128, zero_probability); } while (!mpfr_fits_ulong_p (mpc_realref (z2), MPFR_RNDN)); ul1 = mpfr_get_ui (mpc_realref(z2), MPFR_RNDN); mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: ul1 = 0; break; } break; case CUUC: mpc_set_prec (z2, 128); do { test_default_random (z2, 0, 64, 128, zero_probability); } while (!mpfr_fits_ulong_p (mpc_realref (z2), MPFR_RNDN) ||!mpfr_fits_ulong_p (mpc_imagref (z2), MPFR_RNDN)); ul1 = mpfr_get_ui (mpc_realref(z2), MPFR_RNDN); ul2 = mpfr_get_ui (mpc_imagref(z2), MPFR_RNDN); mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: ul1 = 0; break; case 6: ul2 = 0; break; } break; case CCS: mpc_set_prec (z2, 128); do { test_default_random (z2, 0, 64, 128, zero_probability); } while (!mpfr_fits_slong_p (mpc_realref (z2), MPFR_RNDN)); lo = mpfr_get_si (mpc_realref(z2), MPFR_RNDN); mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: lo = 0; break; } break; case CCI: mpc_set_prec (z2, 128); do { test_default_random (z2, 0, 64, 128, zero_probability); } while (!mpfr_fits_slong_p (mpc_realref (z2), MPFR_RNDN)); i = (int)mpfr_get_si (mpc_realref(z2), MPFR_RNDN); mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: i = 0; break; } break; case CCF: case CFC: mpfr_set_prec (x1, prec); mpfr_set (x1, mpc_realref (z1), MPFR_RNDN); test_default_random (z1, exp_min, exp_max, 128, zero_probability); mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; case 5: mpfr_set_ui (x1, 0, MPFR_RNDN); break; case 6: mpfr_set_inf (x1, +1); break; } break; case CC_C: mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (z4, prec); mpc_set_prec (z5, prec); mpc_set_prec (zzzz, 4*prec); mpc_set_prec (zzzz2, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; } break; case CC: default: mpc_set_prec (z2, prec); mpc_set_prec (z3, prec); mpc_set_prec (zzzz, 4*prec); switch (special) { case 1: mpfr_set_ui (mpc_realref (z1), 0, MPFR_RNDN); break; case 2: mpfr_set_inf (mpc_realref (z1), +1); break; case 3: mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); break; case 4: mpfr_set_inf (mpc_imagref (z1), -1); break; } } for (rnd_re = first_rnd_mode (); is_valid_rnd_mode (rnd_re); rnd_re = next_rnd_mode (rnd_re)) switch (function.type) { case C_CC: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_c_cc (&function, z1, z2, z3, zzzz, z4, MPC_RND (rnd_re, rnd_im)); reuse_c_cc (&function, z1, z2, z3, z4); break; case CCCC: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_cccc (&function, z1, z2, z3, z4, zzzz, z5, MPC_RND (rnd_re, rnd_im)); reuse_cccc (&function, z1, z2, z3, z4, z5); break; case FC: tgeneric_fc (&function, z1, x1, xxxx, x2, rnd_re); reuse_fc (&function, z1, z2, x1); break; case CC: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_cc (&function, z1, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_cc (&function, z1, z2, z3); break; case CC_C: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) for (rnd2_re = first_rnd_mode (); is_valid_rnd_mode (rnd2_re); rnd2_re = next_rnd_mode (rnd2_re)) for (rnd2_im = first_rnd_mode (); is_valid_rnd_mode (rnd2_im); rnd2_im = next_rnd_mode (rnd2_im)) tgeneric_cc_c (&function, z1, z2, z3, zzzz, zzzz2, z4, z5, MPC_RND (rnd_re, rnd_im), MPC_RND (rnd2_re, rnd2_im)); reuse_cc_c (&function, z1, z2, z3, z4, z5); break; case CFC: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_cfc (&function, x1, z1, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_cfc (&function, z1, x1, z2, z3); break; case CCF: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_ccf (&function, z1, x1, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_ccf (&function, z1, x1, z2, z3); break; case CCU: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_ccu (&function, z1, ul1, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_ccu (&function, z1, ul1, z2, z3); break; case CUC: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_cuc (&function, ul1, z1, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_cuc (&function, ul1, z1, z2, z3); break; case CCS: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_ccs (&function, z1, lo, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_ccs (&function, z1, lo, z2, z3); break; case CCI: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_cci (&function, z1, i, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_cci (&function, z1, i, z2, z3); break; case CUUC: for (rnd_im = first_rnd_mode (); is_valid_rnd_mode (rnd_im); rnd_im = next_rnd_mode (rnd_im)) tgeneric_cuuc (&function, ul1, ul2, z1, z2, zzzz, z3, MPC_RND (rnd_re, rnd_im)); reuse_cuuc (&function, ul1, ul2, z1, z2, z3); break; default: printf ("tgeneric not yet implemented for this kind of" "function\n"); exit (1); } } mpc_clear (z1); switch (function.type) { case C_CC: mpc_clear (z2); mpc_clear (z3); mpc_clear (z4); mpc_clear (zzzz); break; case CCCC: mpc_clear (z2); mpc_clear (z3); mpc_clear (z4); mpc_clear (z5); mpc_clear (zzzz); break; case FC: mpc_clear (z2); mpfr_clear (x1); mpfr_clear (x2); mpfr_clear (xxxx); break; case CCF: case CFC: mpfr_clear (x1); mpc_clear (z2); mpc_clear (z3); mpc_clear (zzzz); break; case CC_C: mpc_clear (z2); mpc_clear (z3); mpc_clear (z4); mpc_clear (z5); mpc_clear (zzzz); mpc_clear (zzzz2); break; case CUUC: case CCI: case CCS: case CCU: case CUC: case CC: default: mpc_clear (z2); mpc_clear (z3); mpc_clear (zzzz); } }
/* Compare the result (z1,inex1) of mpfr_pow with all flags cleared with those of mpfr_pow with all flags set and of the other power functions. Arguments x and y are the input values; sx and sy are their string representations (sx may be null); rnd contains the rounding mode; s is a string containing the function that called test_others. */ static void test_others (const void *sx, const char *sy, mpfr_rnd_t rnd, mpfr_srcptr x, mpfr_srcptr y, mpfr_srcptr z1, int inex1, unsigned int flags, const char *s) { mpfr_t z2; int inex2; int spx = sx != NULL; if (!spx) sx = x; mpfr_init2 (z2, mpfr_get_prec (z1)); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_pow (z2, x, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_pow, flags set"); /* If y is an integer that fits in an unsigned long and is not -0, we can test mpfr_pow_ui. */ if (MPFR_IS_POS (y) && mpfr_integer_p (y) && mpfr_fits_ulong_p (y, MPFR_RNDN)) { unsigned long yy = mpfr_get_ui (y, MPFR_RNDN); mpfr_clear_flags (); inex2 = mpfr_pow_ui (z2, x, yy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_pow_ui, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_pow_ui (z2, x, yy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_pow_ui, flags set"); /* If x is an integer that fits in an unsigned long and is not -0, we can also test mpfr_ui_pow_ui. */ if (MPFR_IS_POS (x) && mpfr_integer_p (x) && mpfr_fits_ulong_p (x, MPFR_RNDN)) { unsigned long xx = mpfr_get_ui (x, MPFR_RNDN); mpfr_clear_flags (); inex2 = mpfr_ui_pow_ui (z2, xx, yy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_ui_pow_ui, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_ui_pow_ui (z2, xx, yy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_ui_pow_ui, flags set"); } } /* If y is an integer but not -0 and not huge, we can test mpfr_pow_z, and possibly mpfr_pow_si (and possibly mpfr_ui_div). */ if (MPFR_IS_ZERO (y) ? MPFR_IS_POS (y) : (mpfr_integer_p (y) && MPFR_GET_EXP (y) < 256)) { mpz_t yyy; /* If y fits in a long, we can test mpfr_pow_si. */ if (mpfr_fits_slong_p (y, MPFR_RNDN)) { long yy = mpfr_get_si (y, MPFR_RNDN); mpfr_clear_flags (); inex2 = mpfr_pow_si (z2, x, yy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_pow_si, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_pow_si (z2, x, yy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_pow_si, flags set"); /* If y = -1, we can test mpfr_ui_div. */ if (yy == -1) { mpfr_clear_flags (); inex2 = mpfr_ui_div (z2, 1, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_ui_div, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_ui_div (z2, 1, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_ui_div, flags set"); } /* If y = 2, we can test mpfr_sqr. */ if (yy == 2) { mpfr_clear_flags (); inex2 = mpfr_sqr (z2, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_sqr, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_sqr (z2, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_sqr, flags set"); } } /* Test mpfr_pow_z. */ mpz_init (yyy); mpfr_get_z (yyy, y, MPFR_RNDN); mpfr_clear_flags (); inex2 = mpfr_pow_z (z2, x, yyy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_pow_z, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_pow_z (z2, x, yyy, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_pow_z, flags set"); mpz_clear (yyy); } /* If y = 0.5, we can test mpfr_sqrt, except if x is -0 or -Inf (because the rule for mpfr_pow on these special values is different). */ if (MPFR_IS_PURE_FP (y) && mpfr_cmp_str1 (y, "0.5") == 0 && ! ((MPFR_IS_ZERO (x) || MPFR_IS_INF (x)) && MPFR_IS_NEG (x))) { mpfr_clear_flags (); inex2 = mpfr_sqrt (z2, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_sqrt, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_sqrt (z2, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_sqrt, flags set"); } #if MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0) /* If y = -0.5, we can test mpfr_rec_sqrt, except if x = -Inf (because the rule for mpfr_pow on -Inf is different). */ if (MPFR_IS_PURE_FP (y) && mpfr_cmp_str1 (y, "-0.5") == 0 && ! (MPFR_IS_INF (x) && MPFR_IS_NEG (x))) { mpfr_clear_flags (); inex2 = mpfr_rec_sqrt (z2, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_rec_sqrt, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_rec_sqrt (z2, x, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_rec_sqrt, flags set"); } #endif /* If x is an integer that fits in an unsigned long and is not -0, we can test mpfr_ui_pow. */ if (MPFR_IS_POS (x) && mpfr_integer_p (x) && mpfr_fits_ulong_p (x, MPFR_RNDN)) { unsigned long xx = mpfr_get_ui (x, MPFR_RNDN); mpfr_clear_flags (); inex2 = mpfr_ui_pow (z2, xx, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_ui_pow, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_ui_pow (z2, xx, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_ui_pow, flags set"); /* If x = 2, we can test mpfr_exp2. */ if (xx == 2) { mpfr_clear_flags (); inex2 = mpfr_exp2 (z2, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_exp2, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_exp2 (z2, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_exp2, flags set"); } /* If x = 10, we can test mpfr_exp10. */ if (xx == 10) { mpfr_clear_flags (); inex2 = mpfr_exp10 (z2, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, s, "mpfr_exp10, flags cleared"); __gmpfr_flags = MPFR_FLAGS_ALL; inex2 = mpfr_exp10 (z2, y, rnd); cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, s, "mpfr_exp10, flags set"); } } mpfr_clear (z2); }
/*------------------------------------------------------------------------*/ int my_mpfr_beta (mpfr_t R, mpfr_t a, mpfr_t b, mpfr_rnd_t RND) { mpfr_prec_t p_a = mpfr_get_prec(a), p_b = mpfr_get_prec(b); if(p_a < p_b) p_a = p_b;// p_a := max(p_a, p_b) if(mpfr_get_prec(R) < p_a) mpfr_prec_round(R, p_a, RND);// so prec(R) = max( prec(a), prec(b) ) int ans; mpfr_t s; mpfr_init2(s, p_a); #ifdef DEBUG_Rmpfr R_CheckUserInterrupt(); int cc = 0; #endif /* "FIXME": check each 'ans' below, and return when not ok ... */ ans = mpfr_add(s, a, b, RND); if(mpfr_integer_p(s) && mpfr_sgn(s) <= 0) { // (a + b) is integer <= 0 if(!mpfr_integer_p(a) && !mpfr_integer_p(b)) { // but a,b not integer ==> R = finite / +-Inf = 0 : mpfr_set_zero (R, +1); mpfr_clear (s); return ans; }// else: sum is integer; at least one {a,b} integer ==> both integer int sX = mpfr_sgn(a), sY = mpfr_sgn(b); if(sX * sY < 0) { // one negative, one positive integer // ==> special treatment here : if(sY < 0) // ==> sX > 0; swap the two mpfr_swap(a, b); // now have --- a < 0 < b <= |a| integer ------------------ /* ================ and in this case: B(a,b) = (-1)^b B(1-a-b, b) = (-1)^b B(1-s, b) = (1*2*..*b) / (-s-1)*(-s-2)*...*(-s-b) */ /* where in the 2nd form, both numerator and denominator have exactly * b integer factors. This is attractive {numerically & speed wise} * for 'small' b */ #define b_large 100 #ifdef DEBUG_Rmpfr Rprintf(" my_mpfr_beta(<neg int>): s = a+b= "); R_PRT(s); Rprintf("\n a = "); R_PRT(a); Rprintf("\n b = "); R_PRT(b); Rprintf("\n"); if(cc++ > 999) { mpfr_set_zero (R, +1); mpfr_clear (s); return ans; } #endif unsigned long b_ = 0;// -Wall Rboolean b_fits_ulong = mpfr_fits_ulong_p(b, RND), small_b = b_fits_ulong && (b_ = mpfr_get_ui(b, RND)) < b_large; if(small_b) { #ifdef DEBUG_Rmpfr Rprintf(" b <= b_large = %d...\n", b_large); #endif //----------------- small b ------------------ // use GMP big integer arithmetic: mpz_t S; mpz_init(S); mpfr_get_z(S, s, RND); // S := s mpz_sub_ui (S, S, (unsigned long) 1); // S = s - 1 = (a+b-1) /* binomial coefficient choose(N, k) requires k a 'long int'; * here, b must fit into a long: */ mpz_bin_ui (S, S, b_); // S = choose(S, b) = choose(a+b-1, b) mpz_mul_ui (S, S, b_); // S = S*b = b * choose(a+b-1, b) // back to mpfr: R = 1 / S = 1 / (b * choose(a+b-1, b)) mpfr_set_ui(s, (unsigned long) 1, RND); mpfr_div_z(R, s, S, RND); mpz_clear(S); } else { // b is "large", use direct B(.,.) formula #ifdef DEBUG_Rmpfr Rprintf(" b > b_large = %d...\n", b_large); #endif // a := (-1)^b : // there is no mpfr_si_pow(a, -1, b, RND); int neg; // := 1 ("TRUE") if (-1)^b = -1, i.e. iff b is odd if(b_fits_ulong) { // (i.e. not very large) neg = (b_ % 2); // 1 iff b_ is odd, 0 otherwise } else { // really large b; as we know it is integer, can still.. // b2 := b / 2 mpfr_t b2; mpfr_init2(b2, p_a); mpfr_div_2ui(b2, b, 1, RND); neg = !mpfr_integer_p(b2); // b is odd, if b/2 is *not* integer #ifdef DEBUG_Rmpfr Rprintf(" really large b; neg = ('b is odd') = %d\n", neg); #endif } // s' := 1-s = 1-a-b mpfr_ui_sub(s, 1, s, RND); #ifdef DEBUG_Rmpfr Rprintf(" neg = %d\n", neg); Rprintf(" s' = 1-a-b = "); R_PRT(s); Rprintf("\n -> calling B(s',b)\n"); #endif // R := B(1-a-b, b) = B(s', b) if(small_b) { my_mpfr_beta (R, s, b, RND); } else { my_mpfr_lbeta (R, s, b, RND); mpfr_exp(R, R, RND); // correct *if* beta() >= 0 } #ifdef DEBUG_Rmpfr Rprintf(" R' = beta(s',b) = "); R_PRT(R); Rprintf("\n"); #endif // Result = (-1)^b B(1-a-b, b) = +/- s' if(neg) mpfr_neg(R, R, RND); } mpfr_clear(s); return ans; } } ans = mpfr_gamma(s, s, RND); /* s = gamma(a + b) */ #ifdef DEBUG_Rmpfr Rprintf("my_mpfr_beta(): s = gamma(a+b)= "); R_PRT(s); Rprintf("\n a = "); R_PRT(a); Rprintf("\n b = "); R_PRT(b); #endif ans = mpfr_gamma(a, a, RND); ans = mpfr_gamma(b, b, RND); ans = mpfr_mul(b, b, a, RND); /* b' = gamma(a) * gamma(b) */ #ifdef DEBUG_Rmpfr Rprintf("\n G(a) * G(b) = "); R_PRT(b); Rprintf("\n"); #endif ans = mpfr_div(R, b, s, RND); mpfr_clear (s); /* mpfr_free_cache() must be called in the caller !*/ return ans; }
int my_mpfr_lbeta(mpfr_t R, mpfr_t a, mpfr_t b, mpfr_rnd_t RND) { mpfr_prec_t p_a = mpfr_get_prec(a), p_b = mpfr_get_prec(b); if(p_a < p_b) p_a = p_b;// p_a := max(p_a, p_b) if(mpfr_get_prec(R) < p_a) mpfr_prec_round(R, p_a, RND);// so prec(R) = max( prec(a), prec(b) ) int ans; mpfr_t s; mpfr_init2(s, p_a); /* "FIXME": check each 'ans' below, and return when not ok ... */ ans = mpfr_add(s, a, b, RND); if(mpfr_integer_p(s) && mpfr_sgn(s) <= 0) { // (a + b) is integer <= 0 if(!mpfr_integer_p(a) && !mpfr_integer_p(b)) { // but a,b not integer ==> R = ln(finite / +-Inf) = ln(0) = -Inf : mpfr_set_inf (R, -1); mpfr_clear (s); return ans; }// else: sum is integer; at least one integer ==> both integer int sX = mpfr_sgn(a), sY = mpfr_sgn(b); if(sX * sY < 0) { // one negative, one positive integer // ==> special treatment here : if(sY < 0) // ==> sX > 0; swap the two mpfr_swap(a, b); /* now have --- a < 0 < b <= |a| integer ------------------ * ================ * --> see my_mpfr_beta() above */ unsigned long b_ = 0;// -Wall Rboolean b_fits_ulong = mpfr_fits_ulong_p(b, RND), small_b = b_fits_ulong && (b_ = mpfr_get_ui(b, RND)) < b_large; if(small_b) { //----------------- small b ------------------ // use GMP big integer arithmetic: mpz_t S; mpz_init(S); mpfr_get_z(S, s, RND); // S := s mpz_sub_ui (S, S, (unsigned long) 1); // S = s - 1 = (a+b-1) /* binomial coefficient choose(N, k) requires k a 'long int'; * here, b must fit into a long: */ mpz_bin_ui (S, S, b_); // S = choose(S, b) = choose(a+b-1, b) mpz_mul_ui (S, S, b_); // S = S*b = b * choose(a+b-1, b) // back to mpfr: R = log(|1 / S|) = - log(|S|) mpz_abs(S, S); mpfr_set_z(s, S, RND); // <mpfr> s := |S| mpfr_log(R, s, RND); // R := log(s) = log(|S|) mpfr_neg(R, R, RND); // R = -R = -log(|S|) mpz_clear(S); } else { // b is "large", use direct B(.,.) formula // a := (-1)^b -- not needed here, neither 'neg': want log( |.| ) // s' := 1-s = 1-a-b mpfr_ui_sub(s, 1, s, RND); // R := log(|B(1-a-b, b)|) = log(|B(s', b)|) my_mpfr_lbeta (R, s, b, RND); } mpfr_clear(s); return ans; } } ans = mpfr_lngamma(s, s, RND); // s = lngamma(a + b) ans = mpfr_lngamma(a, a, RND); ans = mpfr_lngamma(b, b, RND); ans = mpfr_add (b, b, a, RND); // b' = lngamma(a) + lngamma(b) ans = mpfr_sub (R, b, s, RND); mpfr_clear (s); return ans; }