mps_boolean mps_quadratic_poly_meval (mps_context * ctx, mps_polynomial * p, mpc_t x, mpc_t value, rdpe_t error) { int i; int m = (int) (log (p->degree + 1.0) / LOG2); rdpe_t ax, rtmp; mpc_t tmp; long int wp = mpc_get_prec (x); /* Correct the working precision in case of a limited precision polynomial (quite unlikely * in the quadratic case, but still. */ if (p->prec > 0 && p->prec < wp) wp = p->prec; if ((1 << m) <= p->degree) m++; mpc_init2 (tmp, wp); mpc_rmod (ax, x); mpc_set_ui (value, 1U, 0U); mpc_rmod (error, value); for (i = 1; i <= m; i++) { mpc_sqr (tmp, value); mpc_mul (value, x, tmp); mpc_add_eq_ui (value, 1U, 0U); rdpe_mul_eq (error, ax); mpc_rmod (rtmp, value); rdpe_add_eq (error, rtmp); } rdpe_set_2dl (rtmp, 1.0, -wp); rdpe_mul_eq (error, rtmp); mpc_clear (tmp); return true; }
static void reuse_bug (void) { mpc_t z1; /* reuse bug found by Paul Zimmermann 20081021 */ mpc_init2 (z1, 2); /* RE (z1^2) overflows, IM(z^2) = -0 */ mpfr_set_str (mpc_realref (z1), "0.11", 2, MPFR_RNDN); mpfr_mul_2si (mpc_realref (z1), mpc_realref (z1), mpfr_get_emax (), MPFR_RNDN); mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN); mpc_conj (z1, z1, MPC_RNDNN); mpc_sqr (z1, z1, MPC_RNDNN); if (!mpfr_inf_p (mpc_realref (z1)) || mpfr_signbit (mpc_realref (z1)) ||!mpfr_zero_p (mpc_imagref (z1)) || !mpfr_signbit (mpc_imagref (z1))) { printf ("Error: Regression, bug 20081021 reproduced\n"); MPC_OUT (z1); exit (1); } mpc_clear (z1); }
int mpc_asin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) { mpfr_prec_t p, p_re, p_im, incr_p = 0; mpfr_rnd_t rnd_re, rnd_im; mpc_t z1; int inex; /* special values */ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op))) { if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op))) { mpfr_set_nan (mpc_realref (rop)); mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? -1 : +1); } else if (mpfr_zero_p (mpc_realref (op))) { mpfr_set (mpc_realref (rop), mpc_realref (op), GMP_RNDN); mpfr_set_nan (mpc_imagref (rop)); } else { mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); } return 0; } if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op))) { int inex_re; if (mpfr_inf_p (mpc_realref (op))) { int inf_im = mpfr_inf_p (mpc_imagref (op)); inex_re = set_pi_over_2 (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd)); mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1)); if (inf_im) mpfr_div_2ui (mpc_realref (rop), mpc_realref (rop), 1, GMP_RNDN); } else { mpfr_set_zero (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1)); inex_re = 0; mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1)); } return MPC_INEX (inex_re, 0); } /* pure real argument */ if (mpfr_zero_p (mpc_imagref (op))) { int inex_re; int inex_im; int s_im; s_im = mpfr_signbit (mpc_imagref (op)); if (mpfr_cmp_ui (mpc_realref (op), 1) > 0) { if (s_im) inex_im = -mpfr_acosh (mpc_imagref (rop), mpc_realref (op), INV_RND (MPC_RND_IM (rnd))); else inex_im = mpfr_acosh (mpc_imagref (rop), mpc_realref (op), MPC_RND_IM (rnd)); inex_re = set_pi_over_2 (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd)); if (s_im) mpc_conj (rop, rop, MPC_RNDNN); } else if (mpfr_cmp_si (mpc_realref (op), -1) < 0) { mpfr_t minus_op_re; minus_op_re[0] = mpc_realref (op)[0]; MPFR_CHANGE_SIGN (minus_op_re); if (s_im) inex_im = -mpfr_acosh (mpc_imagref (rop), minus_op_re, INV_RND (MPC_RND_IM (rnd))); else inex_im = mpfr_acosh (mpc_imagref (rop), minus_op_re, MPC_RND_IM (rnd)); inex_re = set_pi_over_2 (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd)); if (s_im) mpc_conj (rop, rop, MPC_RNDNN); } else { inex_im = mpfr_set_ui (mpc_imagref (rop), 0, MPC_RND_IM (rnd)); if (s_im) mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN); inex_re = mpfr_asin (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd)); } return MPC_INEX (inex_re, inex_im); } /* pure imaginary argument */ if (mpfr_zero_p (mpc_realref (op))) { int inex_im; int s; s = mpfr_signbit (mpc_realref (op)); mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN); if (s) mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN); inex_im = mpfr_asinh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd)); return MPC_INEX (0, inex_im); } /* regular complex: asin(z) = -i*log(i*z+sqrt(1-z^2)) */ p_re = mpfr_get_prec (mpc_realref(rop)); p_im = mpfr_get_prec (mpc_imagref(rop)); rnd_re = MPC_RND_RE(rnd); rnd_im = MPC_RND_IM(rnd); p = p_re >= p_im ? p_re : p_im; mpc_init2 (z1, p); while (1) { mpfr_exp_t ex, ey, err; p += mpc_ceil_log2 (p) + 3 + incr_p; /* incr_p is zero initially */ incr_p = p / 2; mpfr_set_prec (mpc_realref(z1), p); mpfr_set_prec (mpc_imagref(z1), p); /* z1 <- z^2 */ mpc_sqr (z1, op, MPC_RNDNN); /* err(x) <= 1/2 ulp(x), err(y) <= 1/2 ulp(y) */ /* z1 <- 1-z1 */ ex = mpfr_get_exp (mpc_realref(z1)); mpfr_ui_sub (mpc_realref(z1), 1, mpc_realref(z1), GMP_RNDN); mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN); ex = ex - mpfr_get_exp (mpc_realref(z1)); ex = (ex <= 0) ? 0 : ex; /* err(x) <= 2^ex * ulp(x) */ ex = ex + mpfr_get_exp (mpc_realref(z1)) - p; /* err(x) <= 2^ex */ ey = mpfr_get_exp (mpc_imagref(z1)) - p - 1; /* err(y) <= 2^ey */ ex = (ex >= ey) ? ex : ey; /* err(x), err(y) <= 2^ex, i.e., the norm of the error is bounded by |h|<=2^(ex+1/2) */ /* z1 <- sqrt(z1): if z1 = z + h, then sqrt(z1) = sqrt(z) + h/2/sqrt(t) */ ey = mpfr_get_exp (mpc_realref(z1)) >= mpfr_get_exp (mpc_imagref(z1)) ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1)); /* we have |z1| >= 2^(ey-1) thus 1/|z1| <= 2^(1-ey) */ mpc_sqrt (z1, z1, MPC_RNDNN); ex = (2 * ex + 1) - 2 - (ey - 1); /* |h^2/4/|t| <= 2^ex */ ex = (ex + 1) / 2; /* ceil(ex/2) */ /* express ex in terms of ulp(z1) */ ey = mpfr_get_exp (mpc_realref(z1)) <= mpfr_get_exp (mpc_imagref(z1)) ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1)); ex = ex - ey + p; /* take into account the rounding error in the mpc_sqrt call */ err = (ex <= 0) ? 1 : ex + 1; /* err(x) <= 2^err * ulp(x), err(y) <= 2^err * ulp(y) */ /* z1 <- i*z + z1 */ ex = mpfr_get_exp (mpc_realref(z1)); ey = mpfr_get_exp (mpc_imagref(z1)); mpfr_sub (mpc_realref(z1), mpc_realref(z1), mpc_imagref(op), GMP_RNDN); mpfr_add (mpc_imagref(z1), mpc_imagref(z1), mpc_realref(op), GMP_RNDN); if (mpfr_cmp_ui (mpc_realref(z1), 0) == 0 || mpfr_cmp_ui (mpc_imagref(z1), 0) == 0) continue; ex -= mpfr_get_exp (mpc_realref(z1)); /* cancellation in x */ ey -= mpfr_get_exp (mpc_imagref(z1)); /* cancellation in y */ ex = (ex >= ey) ? ex : ey; /* maximum cancellation */ err += ex; err = (err <= 0) ? 1 : err + 1; /* rounding error in sub/add */ /* z1 <- log(z1): if z1 = z + h, then log(z1) = log(z) + h/t with |t| >= min(|z1|,|z|) */ ex = mpfr_get_exp (mpc_realref(z1)); ey = mpfr_get_exp (mpc_imagref(z1)); ex = (ex >= ey) ? ex : ey; err += ex - p; /* revert to absolute error <= 2^err */ mpc_log (z1, z1, GMP_RNDN); err -= ex - 1; /* 1/|t| <= 1/|z| <= 2^(1-ex) */ /* express err in terms of ulp(z1) */ ey = mpfr_get_exp (mpc_realref(z1)) <= mpfr_get_exp (mpc_imagref(z1)) ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1)); err = err - ey + p; /* take into account the rounding error in the mpc_log call */ err = (err <= 0) ? 1 : err + 1; /* z1 <- -i*z1 */ mpfr_swap (mpc_realref(z1), mpc_imagref(z1)); mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN); if (mpfr_can_round (mpc_realref(z1), p - err, GMP_RNDN, GMP_RNDZ, p_re + (rnd_re == GMP_RNDN)) && mpfr_can_round (mpc_imagref(z1), p - err, GMP_RNDN, GMP_RNDZ, p_im + (rnd_im == GMP_RNDN))) break; } inex = mpc_set (rop, z1, rnd); mpc_clear (z1); return inex; }
/****************************************************** * SUBROUTINE MNEWTON_USR * ******************************************************* multiprecision computation ******************************************************/ void mnewton_usr (mpc_t x, rdpe_t rad, mpc_t corr, mps_boolean * again) { int i, m; rdpe_t ap, ax, eps, temp, apeps, atmp; cdpe_t ctmp; tmpc_t p, pp, pt, tmp; tmpc_init2 (p, mpwp); tmpc_init2 (pp, mpwp); tmpc_init2 (pt, mpwp); tmpc_init2 (tmp, mpwp); m = (int) (log (n + 1.0) / LOG2); if ((1 << m) <= n) m++; rdpe_set (eps, mp_epsilon); rdpe_mul_eq_d (eps, (double) 4 * n); mpc_get_cdpe (ctmp, x); cdpe_mod (ax, ctmp); mpc_set_ui (p, 1, 0); mpc_set_ui (pp, 0, 0); rdpe_set (ap, rdpe_one); for (i = 1; i <= m; i++) { mpc_sqr (tmp, p); mpc_mul (pt, x, tmp); mpc_add_eq_ui (pt, 1, 0); mpc_mul_eq (pp, x); mpc_mul_eq (pp, p); mpc_mul_eq_ui (pp, 2); mpc_add_eq (pp, tmp); mpc_set (p, pt); rdpe_mul_eq (ap, ax); mpc_get_cdpe (ctmp, p); cdpe_mod (atmp, ctmp); rdpe_add_eq (ap, atmp); } rdpe_mul_eq (ap, ax); mpc_div (corr, p, pp); mpc_get_cdpe (ctmp, p); cdpe_mod (temp, ctmp); rdpe_mul (apeps, ap, eps); rdpe_mul_eq_d (apeps, 3.0); *again = rdpe_gt (temp, apeps); rdpe_add (rad, temp, apeps); rdpe_mul_eq_d (rad, (double) n); mpc_get_cdpe (ctmp, pp); cdpe_mod (temp, ctmp); rdpe_div_eq (rad, temp); if (rdpe_eq (rad, rdpe_zero)) rdpe_mul (rad, ax, eps); tmpc_clear (tmp); tmpc_clear (pt); tmpc_clear (pp); tmpc_clear (p); }
static void cmpsqr (mpc_srcptr x, mpc_rnd_t rnd) /* computes the square of x with the specific function or by simple */ /* multiplication using the rounding mode rnd and compares the results */ /* and return values. */ /* In our current test suite, the real and imaginary parts of x have */ /* the same precision, and we use this precision also for the result. */ /* Furthermore, we check whether computing the square in the same */ /* place yields the same result. */ /* We also compute the result with four times the precision and check */ /* whether the rounding is correct. Error reports in this part of the */ /* algorithm might still be wrong, though, since there are two */ /* consecutive roundings. */ { mpc_t z, t, u; int inexact_z, inexact_t; mpc_init2 (z, MPC_MAX_PREC (x)); mpc_init2 (t, MPC_MAX_PREC (x)); mpc_init2 (u, 4 * MPC_MAX_PREC (x)); inexact_z = mpc_sqr (z, x, rnd); inexact_t = mpc_mul (t, x, x, rnd); if (mpc_cmp (z, t)) { fprintf (stderr, "sqr and mul differ for rnd=(%s,%s) \nx=", mpfr_print_rnd_mode(MPC_RND_RE(rnd)), mpfr_print_rnd_mode(MPC_RND_IM(rnd))); mpc_out_str (stderr, 2, 0, x, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr gives "); mpc_out_str (stderr, 2, 0, z, MPC_RNDNN); fprintf (stderr, "\nmpc_mul gives "); mpc_out_str (stderr, 2, 0, t, MPC_RNDNN); fprintf (stderr, "\n"); exit (1); } if (inexact_z != inexact_t) { fprintf (stderr, "The return values of sqr and mul differ for rnd=(%s,%s) \nx= ", mpfr_print_rnd_mode(MPC_RND_RE(rnd)), mpfr_print_rnd_mode(MPC_RND_IM(rnd))); mpc_out_str (stderr, 2, 0, x, MPC_RNDNN); fprintf (stderr, "\nx^2="); mpc_out_str (stderr, 2, 0, z, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr gives %i", inexact_z); fprintf (stderr, "\nmpc_mul gives %i", inexact_t); fprintf (stderr, "\n"); exit (1); } mpc_set (t, x, MPC_RNDNN); inexact_t = mpc_sqr (t, t, rnd); if (mpc_cmp (z, t)) { fprintf (stderr, "sqr and sqr in place differ for rnd=(%s,%s) \nx=", mpfr_print_rnd_mode(MPC_RND_RE(rnd)), mpfr_print_rnd_mode(MPC_RND_IM(rnd))); mpc_out_str (stderr, 2, 0, x, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr gives "); mpc_out_str (stderr, 2, 0, z, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr in place gives "); mpc_out_str (stderr, 2, 0, t, MPC_RNDNN); fprintf (stderr, "\n"); exit (1); } if (inexact_z != inexact_t) { fprintf (stderr, "The return values of sqr and sqr in place differ for rnd=(%s,%s) \nx= ", mpfr_print_rnd_mode(MPC_RND_RE(rnd)), mpfr_print_rnd_mode(MPC_RND_IM(rnd))); mpc_out_str (stderr, 2, 0, x, MPC_RNDNN); fprintf (stderr, "\nx^2="); mpc_out_str (stderr, 2, 0, z, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr gives %i", inexact_z); fprintf (stderr, "\nmpc_sqr in place gives %i", inexact_t); fprintf (stderr, "\n"); exit (1); } mpc_sqr (u, x, rnd); mpc_set (t, u, rnd); if (mpc_cmp (z, t)) { fprintf (stderr, "rounding in sqr might be incorrect for rnd=(%s,%s) \nx=", mpfr_print_rnd_mode(MPC_RND_RE(rnd)), mpfr_print_rnd_mode(MPC_RND_IM(rnd))); mpc_out_str (stderr, 2, 0, x, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr gives "); mpc_out_str (stderr, 2, 0, z, MPC_RNDNN); fprintf (stderr, "\nmpc_sqr quadruple precision gives "); mpc_out_str (stderr, 2, 0, u, MPC_RNDNN); fprintf (stderr, "\nand is rounded to "); mpc_out_str (stderr, 2, 0, t, MPC_RNDNN); fprintf (stderr, "\n"); exit (1); } mpc_clear (z); mpc_clear (t); mpc_clear (u); }
/** * @brief User-defined program for the computation of \f$p\f$, \f$p'\f$. * * @param s The current mps_context * @param poly The mps_polynomial being solved. * @param root The approximation whose Newton correction shall be computed. * @param corr The output value where the newton correction will be stored. * * This sample computes the 'Quadratic polynomial by * means of the relation: p=1+x*p**2, starting with p=1 */ void mps_quadratic_poly_mnewton (mps_context * ctx, mps_polynomial * poly, mps_approximation * root, mpc_t corr, long int wp) { int i, m, n = poly->degree; rdpe_t ap, ax, eps, temp, apeps, atmp, epsilon, drad; cdpe_t ctmp; mpc_t p, pp, pt, tmp, x; mps_boolean again; mpc_init2 (p, wp); mpc_init2 (pp, wp); mpc_init2 (pt, wp); mpc_init2 (tmp, wp); mpc_init2 (x, wp); mps_approximation_get_mvalue (ctx, root, x); mps_approximation_get_drad (ctx, root, drad); again = mps_approximation_get_again (ctx, root); rdpe_set_2dl (epsilon, 1.0, 2 - wp); m = (int) (log (n + 1.0) / LOG2); if ((1 << m) <= n) m++; rdpe_set (eps, epsilon); rdpe_mul_eq_d (eps, (double) 4 * n); mpc_get_cdpe (ctmp, x); cdpe_mod (ax, ctmp); mpc_set_ui (p, 1, 0); mpc_set_ui (pp, 0, 0); rdpe_set (ap, rdpe_one); for (i = 1; i <= m; i++) { mpc_sqr (tmp, p); mpc_mul (pt, x, tmp); mpc_add_eq_ui (pt, 1, 0); mpc_mul_eq (pp, x); mpc_mul_eq (pp, p); mpc_mul_eq_ui (pp, 2); mpc_add_eq (pp, tmp); mpc_set (p, pt); rdpe_mul_eq (ap, ax); mpc_get_cdpe (ctmp, p); cdpe_mod (atmp, ctmp); rdpe_add_eq (ap, atmp); } rdpe_mul_eq (ap, ax); mpc_div (corr, p, pp); mpc_get_cdpe (ctmp, p); cdpe_mod (temp, ctmp); rdpe_mul (apeps, ap, eps); rdpe_mul_eq_d (apeps, 3.0); mps_approximation_set_again (ctx, root, rdpe_gt (temp, apeps)); rdpe_add (drad, temp, apeps); rdpe_mul_eq_d (drad, (double) n); mpc_get_cdpe (ctmp, pp); cdpe_mod (temp, ctmp); rdpe_div_eq (drad, temp); if (rdpe_eq (drad, rdpe_zero)) rdpe_mul (drad, ax, eps); mps_approximation_set_drad (ctx, root, drad); mps_approximation_set_again (ctx, root, again); mpc_clear (tmp); mpc_clear (pt); mpc_clear (pp); mpc_clear (p); mpc_clear (x); }
void mpcomplex::sqr3() { mpc_sqr(mpc_val, mpc_val, default_rnd); }