diff options
author | pelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4> | 2005-02-14 10:54:42 +0000 |
---|---|---|
committer | pelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4> | 2005-02-14 10:54:42 +0000 |
commit | 6f9d3e893ed8be67f342b5af153783340f9a1a67 (patch) | |
tree | 629cdb848f680e1f55c4406f6f115ff2adff1b85 /erf.c | |
parent | 1d432ab5f17738d6729af5c225ef410c672225f3 (diff) | |
download | mpfr-6f9d3e893ed8be67f342b5af153783340f9a1a67.tar.gz |
Clean up code.
Fix bug with Exponent range.
Add ZivLoop controller.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3299 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'erf.c')
-rw-r--r-- | erf.c | 110 |
1 files changed, 50 insertions, 60 deletions
@@ -27,30 +27,27 @@ MA 02111-1307, USA. */ #define EXP1 2.71828182845904523536 /* exp(1) */ -static int mpfr_erf_0 (mpfr_ptr, mpfr_srcptr, mp_rnd_t); +static int mpfr_erf_0 (mpfr_ptr, mpfr_srcptr, double, mp_rnd_t); int mpfr_erf (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) { double xf; - int sign_x; - mp_rnd_t rnd2; - double n = (double) MPFR_PREC(y); int inex; + MPFR_SAVE_EXPO_DECL (expo); - sign_x = MPFR_SIGN (x); - if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(x) )) + if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { - if (MPFR_IS_NAN(x)) + if (MPFR_IS_NAN (x)) { - MPFR_SET_NAN(y); + MPFR_SET_NAN (y); MPFR_RET_NAN; } - else if (MPFR_IS_INF(x)) /* erf(+inf) = +1, erf(-inf) = -1 */ - return mpfr_set_si (y, MPFR_FROM_SIGN_TO_INT(sign_x), GMP_RNDN); + else if (MPFR_IS_INF (x)) /* erf(+inf) = +1, erf(-inf) = -1 */ + return mpfr_set_si (y, MPFR_INT_SIGN (x), GMP_RNDN); else /* erf(+0) = +0, erf(-0) = -0 */ { - MPFR_ASSERTD(MPFR_IS_ZERO(x)); + MPFR_ASSERTD (MPFR_IS_ZERO (x)); return mpfr_set (y, x, GMP_RNDN); /* should keep the sign of x */ } } @@ -60,39 +57,31 @@ mpfr_erf (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) xf = mpfr_get_d (x, GMP_RNDN); xf = xf * xf; /* xf ~ x^2 */ - rnd2 = MPFR_IS_POS_SIGN(sign_x) ? rnd_mode : MPFR_INVERT_RND(rnd_mode); - /* use expansion at x=0 when e*x^2 <= n (target precision) otherwise use asymptotic expansion */ + MPFR_SAVE_EXPO_MARK (expo); - if (xf > n * LOG2) /* |erf x| = 1 or 1- */ + if (MPFR_UNLIKELY (xf > LOG2 * ((double) MPFR_PREC (y)))) + /* |erf x| = 1 or 1- */ { + mp_rnd_t rnd2 = MPFR_IS_POS (x) ? rnd_mode : MPFR_INVERT_RND(rnd_mode); if (rnd2 == GMP_RNDN || rnd2 == GMP_RNDU) { - if (MPFR_IS_POS_SIGN(sign_x)) - { - mpfr_set_ui (y, 1, rnd2); - inex = 1; - } - else - { - mpfr_set_si (y, -1, rnd2); - inex = -1; - } + inex = MPFR_INT_SIGN (x); + mpfr_set_si (y, inex, rnd2); } else /* round to zero */ { + inex = -MPFR_INT_SIGN (x); mpfr_setmax (y, 0); /* warning: setmax keeps the old sign of y */ - MPFR_SET_SAME_SIGN(y, x); - inex = MPFR_IS_POS_SIGN(sign_x) ? -1 : 1; + MPFR_SET_SAME_SIGN (y, x); } } else /* use Taylor */ - { - inex = mpfr_erf_0 (y, x, rnd_mode); - } + inex = mpfr_erf_0 (y, x, xf, rnd_mode); - return inex; + MPFR_SAVE_EXPO_FREE (expo); + return mpfr_check_range (y, inex, rnd_mode); } /* return x*2^e */ @@ -121,41 +110,33 @@ mul_2exp (double x, mp_exp_t e) Assumes also that e*x^2 <= n (target precision). */ static int -mpfr_erf_0 (mpfr_ptr res, mpfr_srcptr x, mp_rnd_t rnd_mode) +mpfr_erf_0 (mpfr_ptr res, mpfr_srcptr x, double xf2, mp_rnd_t rnd_mode) { mp_prec_t n, m; mp_exp_t nuk, sigmak; - double xf, tauk; + double tauk; mpfr_t y, s, t, u; unsigned int k; - long log2tauk; - int ok; + int log2tauk; int inex; + MPFR_ZIV_DECL (loop); - n = MPFR_PREC(res); /* target precision */ - xf = mpfr_get_d (x, GMP_RNDN); + n = MPFR_PREC (res); /* target precision */ /* initial working precision */ - m = n + (mp_prec_t) (xf * xf / LOG2) + 8; + m = n + (mp_prec_t) (xf2 / LOG2) + 8 + MPFR_INT_CEIL_LOG2 (n); - mpfr_init2 (y, 2); - mpfr_init2 (s, 2); - mpfr_init2 (t, 2); - mpfr_init2 (u, 2); + mpfr_init2 (y, m); + mpfr_init2 (s, m); + mpfr_init2 (t, m); + mpfr_init2 (u, m); - do + MPFR_ZIV_INIT (loop, m); + for (;;) { - - m += MPFR_INT_CEIL_LOG2 (n); - - mpfr_set_prec (y, m); - mpfr_set_prec (s, m); - mpfr_set_prec (t, m); - mpfr_set_prec (u, m); - mpfr_mul (y, x, x, GMP_RNDU); /* err <= 1 ulp */ - mpfr_set_ui (s, 1, GMP_RNDN); /* exact */ - mpfr_set_ui (t, 1, GMP_RNDN); /* exact */ + mpfr_set_ui (s, 1, GMP_RNDN); + mpfr_set_ui (t, 1, GMP_RNDN); tauk = 0.0; for (k = 1; ; k++) @@ -163,15 +144,15 @@ mpfr_erf_0 (mpfr_ptr res, mpfr_srcptr x, mp_rnd_t rnd_mode) mpfr_mul (t, y, t, GMP_RNDU); mpfr_div_ui (t, t, k, GMP_RNDU); mpfr_div_ui (u, t, 2 * k + 1, GMP_RNDU); - sigmak = MPFR_EXP(s); + sigmak = MPFR_GET_EXP (s); if (k % 2) mpfr_sub (s, s, u, GMP_RNDN); else mpfr_add (s, s, u, GMP_RNDN); - sigmak -= MPFR_EXP(s); - nuk = MPFR_EXP(u) - MPFR_EXP(s); + sigmak -= MPFR_GET_EXP(s); + nuk = MPFR_GET_EXP(u) - MPFR_GET_EXP(s); - if ((nuk < - (mp_exp_t) m) && ((double) k >= xf * xf)) + if ((nuk < - (mp_exp_t) m) && ((double) k >= xf2)) break; /* tauk <- 1/2 + tauk * 2^sigmak + (1+8k)*2^nuk */ @@ -180,7 +161,7 @@ mpfr_erf_0 (mpfr_ptr res, mpfr_srcptr x, mp_rnd_t rnd_mode) } mpfr_mul (s, x, s, GMP_RNDU); - MPFR_EXP(s) ++; + MPFR_SET_EXP (s, MPFR_GET_EXP (s) + 1); mpfr_const_pi (t, GMP_RNDZ); mpfr_sqrt (t, t, GMP_RNDZ); @@ -188,10 +169,19 @@ mpfr_erf_0 (mpfr_ptr res, mpfr_srcptr x, mp_rnd_t rnd_mode) tauk = 4.0 * tauk + 11.0; /* final ulp-error on s */ log2tauk = __gmpfr_ceil_log2 (tauk); - ok = mpfr_can_round (s, m - log2tauk, GMP_RNDN, GMP_RNDZ, - n + (rnd_mode == GMP_RNDN)); + if (MPFR_LIKELY (mpfr_can_round (s, m - log2tauk, GMP_RNDN, GMP_RNDZ, + n + (rnd_mode == GMP_RNDN)))) + break; + + /* Actualisation of the precision */ + MPFR_ZIV_NEXT (loop, m); + mpfr_set_prec (y, m); + mpfr_set_prec (s, m); + mpfr_set_prec (t, m); + mpfr_set_prec (u, m); + } - while (ok == 0); + MPFR_ZIV_FREE (loop); inex = mpfr_set (res, s, rnd_mode); |