static PyObject * GMPy_Complex_Abs(PyObject *x, CTXT_Object *context) { MPFR_Object *result = NULL; MPC_Object *tempx = NULL; CHECK_CONTEXT(context); if (!(tempx = GMPy_MPC_From_Complex(x, 1, 1, context)) || !(result = GMPy_MPFR_New(0, context))) { /* LCOV_EXCL_START */ Py_XDECREF((PyObject*)tempx); Py_XDECREF((PyObject*)result); return NULL; /* LCOV_EXCL_STOP */ } mpfr_clear_flags(); SET_MPC_WAS_NAN(context, tempx); result->rc = mpc_abs(result->f, tempx->c, GET_MPC_ROUND(context)); Py_DECREF((PyObject*)tempx); _GMPy_MPFR_Cleanup(&result, context); return (PyObject*)result; }
/* the rounding mode is mpfr_rnd_t here since we return an mpfr number */ int mpc_norm (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd) { mpfr_t u, v; mp_prec_t prec; int inexact, overflow; prec = MPFR_PREC(a); /* handling of special values; consistent with abs in that norm = abs^2; so norm (+-inf, nan) = norm (nan, +-inf) = +inf */ if ( (mpfr_nan_p (MPC_RE (b)) || mpfr_nan_p (MPC_IM (b))) || (mpfr_inf_p (MPC_RE (b)) || mpfr_inf_p (MPC_IM (b)))) return mpc_abs (a, b, rnd); mpfr_init (u); mpfr_init (v); if (!mpfr_zero_p(MPC_RE(b)) && !mpfr_zero_p(MPC_IM(b)) && 2 * SAFE_ABS (mp_exp_t, MPFR_EXP (MPC_RE (b)) - MPFR_EXP (MPC_IM (b))) > (mp_exp_t)prec) /* If real and imaginary part have very different magnitudes, then the */ /* generic code increases the precision too much. Instead, compute the */ /* squarings _exactly_. */ { mpfr_set_prec (u, 2 * MPFR_PREC (MPC_RE (b))); mpfr_set_prec (v, 2 * MPFR_PREC (MPC_IM (b))); mpfr_sqr (u, MPC_RE (b), GMP_RNDN); mpfr_sqr (v, MPC_IM (b), GMP_RNDN); inexact = mpfr_add (a, u, v, rnd); } else { do { prec += mpc_ceil_log2 (prec) + 3; mpfr_set_prec (u, prec); mpfr_set_prec (v, prec); inexact = mpfr_sqr (u, MPC_RE(b), GMP_RNDN); /* err<=1/2ulp */ inexact |= mpfr_sqr (v, MPC_IM(b), GMP_RNDN); /* err<=1/2ulp*/ inexact |= mpfr_add (u, u, v, GMP_RNDN); /* err <= 3/2 ulps */ overflow = mpfr_inf_p (u); } while (!overflow && inexact && mpfr_can_round (u, prec - 2, GMP_RNDN, rnd, MPFR_PREC(a)) == 0); inexact |= mpfr_set (a, u, rnd); } mpfr_clear (u); mpfr_clear (v); return inexact; }
int mpc_sqrt (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd) { int ok_w, ok_t = 0; mpfr_t w, t; mp_rnd_t rnd_w, rnd_t; mp_prec_t prec_w, prec_t; /* the rounding mode and the precision required for w and t, which can */ /* be either the real or the imaginary part of a */ mp_prec_t prec; int inex_w, inex_t = 1, inex, loops = 0; /* comparison of the real/imaginary part of b with 0 */ const int re_cmp = mpfr_cmp_ui (MPC_RE (b), 0); const int im_cmp = mpfr_cmp_ui (MPC_IM (b), 0); /* we need to know the sign of Im(b) when it is +/-0 */ const int im_sgn = mpfr_signbit (MPC_IM (b)) == 0? 0 : -1; /* special values */ /* sqrt(x +i*Inf) = +Inf +I*Inf, even if x = NaN */ /* sqrt(x -i*Inf) = +Inf -I*Inf, even if x = NaN */ if (mpfr_inf_p (MPC_IM (b))) { mpfr_set_inf (MPC_RE (a), +1); mpfr_set_inf (MPC_IM (a), im_sgn); return MPC_INEX (0, 0); } if (mpfr_inf_p (MPC_RE (b))) { if (mpfr_signbit (MPC_RE (b))) { if (mpfr_number_p (MPC_IM (b))) { /* sqrt(-Inf +i*y) = +0 +i*Inf, when y positive */ /* sqrt(-Inf +i*y) = +0 -i*Inf, when y positive */ mpfr_set_ui (MPC_RE (a), 0, GMP_RNDN); mpfr_set_inf (MPC_IM (a), im_sgn); return MPC_INEX (0, 0); } else { /* sqrt(-Inf +i*NaN) = NaN +/-i*Inf */ mpfr_set_nan (MPC_RE (a)); mpfr_set_inf (MPC_IM (a), im_sgn); return MPC_INEX (0, 0); } } else { if (mpfr_number_p (MPC_IM (b))) { /* sqrt(+Inf +i*y) = +Inf +i*0, when y positive */ /* sqrt(+Inf +i*y) = +Inf -i*0, when y positive */ mpfr_set_inf (MPC_RE (a), +1); mpfr_set_ui (MPC_IM (a), 0, GMP_RNDN); if (im_sgn) mpc_conj (a, a, MPC_RNDNN); return MPC_INEX (0, 0); } else { /* sqrt(+Inf -i*Inf) = +Inf -i*Inf */ /* sqrt(+Inf +i*Inf) = +Inf +i*Inf */ /* sqrt(+Inf +i*NaN) = +Inf +i*NaN */ return mpc_set (a, b, rnd); } } } /* sqrt(x +i*NaN) = NaN +i*NaN, if x is not infinite */ /* sqrt(NaN +i*y) = NaN +i*NaN, if y is not infinite */ if (mpfr_nan_p (MPC_RE (b)) || mpfr_nan_p (MPC_IM (b))) { mpfr_set_nan (MPC_RE (a)); mpfr_set_nan (MPC_IM (a)); return MPC_INEX (0, 0); } /* purely real */ if (im_cmp == 0) { if (re_cmp == 0) { mpc_set_ui_ui (a, 0, 0, MPC_RNDNN); if (im_sgn) mpc_conj (a, a, MPC_RNDNN); return MPC_INEX (0, 0); } else if (re_cmp > 0) { inex_w = mpfr_sqrt (MPC_RE (a), MPC_RE (b), MPC_RND_RE (rnd)); mpfr_set_ui (MPC_IM (a), 0, GMP_RNDN); if (im_sgn) mpc_conj (a, a, MPC_RNDNN); return MPC_INEX (inex_w, 0); } else { mpfr_init2 (w, MPFR_PREC (MPC_RE (b))); mpfr_neg (w, MPC_RE (b), GMP_RNDN); if (im_sgn) { inex_w = -mpfr_sqrt (MPC_IM (a), w, INV_RND (MPC_RND_IM (rnd))); mpfr_neg (MPC_IM (a), MPC_IM (a), GMP_RNDN); } else inex_w = mpfr_sqrt (MPC_IM (a), w, MPC_RND_IM (rnd)); mpfr_set_ui (MPC_RE (a), 0, GMP_RNDN); mpfr_clear (w); return MPC_INEX (0, inex_w); } } /* purely imaginary */ if (re_cmp == 0) { mpfr_t y; y[0] = MPC_IM (b)[0]; /* If y/2 underflows, so does sqrt(y/2) */ mpfr_div_2ui (y, y, 1, GMP_RNDN); if (im_cmp > 0) { inex_w = mpfr_sqrt (MPC_RE (a), y, MPC_RND_RE (rnd)); inex_t = mpfr_sqrt (MPC_IM (a), y, MPC_RND_IM (rnd)); } else { mpfr_neg (y, y, GMP_RNDN); inex_w = mpfr_sqrt (MPC_RE (a), y, MPC_RND_RE (rnd)); inex_t = -mpfr_sqrt (MPC_IM (a), y, INV_RND (MPC_RND_IM (rnd))); mpfr_neg (MPC_IM (a), MPC_IM (a), GMP_RNDN); } return MPC_INEX (inex_w, inex_t); } prec = MPC_MAX_PREC(a); mpfr_init (w); mpfr_init (t); if (re_cmp >= 0) { rnd_w = MPC_RND_RE (rnd); prec_w = MPFR_PREC (MPC_RE (a)); rnd_t = MPC_RND_IM(rnd); prec_t = MPFR_PREC (MPC_IM (a)); } else { rnd_w = MPC_RND_IM(rnd); prec_w = MPFR_PREC (MPC_IM (a)); rnd_t = MPC_RND_RE(rnd); prec_t = MPFR_PREC (MPC_RE (a)); if (im_cmp < 0) { rnd_w = INV_RND(rnd_w); rnd_t = INV_RND(rnd_t); } } do { loops ++; prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2; mpfr_set_prec (w, prec); mpfr_set_prec (t, prec); /* let b = x + iy */ /* w = sqrt ((|x| + sqrt (x^2 + y^2)) / 2), rounded down */ /* total error bounded by 3 ulps */ inex_w = mpc_abs (w, b, GMP_RNDD); if (re_cmp < 0) inex_w |= mpfr_sub (w, w, MPC_RE (b), GMP_RNDD); else inex_w |= mpfr_add (w, w, MPC_RE (b), GMP_RNDD); inex_w |= mpfr_div_2ui (w, w, 1, GMP_RNDD); inex_w |= mpfr_sqrt (w, w, GMP_RNDD); ok_w = mpfr_can_round (w, (mp_exp_t) prec - 2, GMP_RNDD, GMP_RNDU, prec_w + (rnd_w == GMP_RNDN)); if (!inex_w || ok_w) { /* t = y / 2w, rounded away */ /* total error bounded by 7 ulps */ const mp_rnd_t r = im_sgn ? GMP_RNDD : GMP_RNDU; inex_t = mpfr_div (t, MPC_IM (b), w, r); inex_t |= mpfr_div_2ui (t, t, 1, r); ok_t = mpfr_can_round (t, (mp_exp_t) prec - 3, r, GMP_RNDZ, prec_t + (rnd_t == GMP_RNDN)); /* As for w; since t was rounded away, we check whether rounding to 0 is possible. */ } } while ((inex_w && !ok_w) || (inex_t && !ok_t)); if (re_cmp > 0) inex = MPC_INEX (mpfr_set (MPC_RE (a), w, MPC_RND_RE(rnd)), mpfr_set (MPC_IM (a), t, MPC_RND_IM(rnd))); else if (im_cmp > 0) inex = MPC_INEX (mpfr_set (MPC_RE(a), t, MPC_RND_RE(rnd)), mpfr_set (MPC_IM(a), w, MPC_RND_IM(rnd))); else inex = MPC_INEX (mpfr_neg (MPC_RE (a), t, MPC_RND_RE(rnd)), mpfr_neg (MPC_IM (a), w, MPC_RND_IM(rnd))); mpfr_clear (w); mpfr_clear (t); return inex; }
int mpc_log (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd){ int ok, underflow = 0; mpfr_srcptr x, y; mpfr_t v, w; mpfr_prec_t prec; int loops; int re_cmp, im_cmp; int inex_re, inex_im; int err; mpfr_exp_t expw; int sgnw; /* special values: NaN and infinities */ if (!mpc_fin_p (op)) { if (mpfr_nan_p (mpc_realref (op))) { if (mpfr_inf_p (mpc_imagref (op))) mpfr_set_inf (mpc_realref (rop), +1); else mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); inex_im = 0; /* Inf/NaN is exact */ } else if (mpfr_nan_p (mpc_imagref (op))) { if (mpfr_inf_p (mpc_realref (op))) mpfr_set_inf (mpc_realref (rop), +1); else mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); inex_im = 0; /* Inf/NaN is exact */ } else /* We have an infinity in at least one part. */ { inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op), MPC_RND_IM (rnd)); mpfr_set_inf (mpc_realref (rop), +1); } return MPC_INEX(0, inex_im); } /* special cases: real and purely imaginary numbers */ re_cmp = mpfr_cmp_ui (mpc_realref (op), 0); im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0); if (im_cmp == 0) { if (re_cmp == 0) { inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op), MPC_RND_IM (rnd)); mpfr_set_inf (mpc_realref (rop), -1); inex_re = 0; /* -Inf is exact */ } else if (re_cmp > 0) { inex_re = mpfr_log (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd)); inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd)); } else { /* op = x + 0*y; let w = -x = |x| */ int negative_zero; mpfr_rnd_t rnd_im; negative_zero = mpfr_signbit (mpc_imagref (op)); if (negative_zero) rnd_im = INV_RND (MPC_RND_IM (rnd)); else rnd_im = MPC_RND_IM (rnd); w [0] = *mpc_realref (op); MPFR_CHANGE_SIGN (w); inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd)); inex_im = mpfr_const_pi (mpc_imagref (rop), rnd_im); if (negative_zero) { mpc_conj (rop, rop, MPC_RNDNN); inex_im = -inex_im; } } return MPC_INEX(inex_re, inex_im); } else if (re_cmp == 0) { if (im_cmp > 0) { inex_re = mpfr_log (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE (rnd)); inex_im = mpfr_const_pi (mpc_imagref (rop), MPC_RND_IM (rnd)); /* division by 2 does not change the ternary flag */ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN); } else { w [0] = *mpc_imagref (op); MPFR_CHANGE_SIGN (w); inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd)); inex_im = mpfr_const_pi (mpc_imagref (rop), INV_RND (MPC_RND_IM (rnd))); /* division by 2 does not change the ternary flag */ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN); mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN); inex_im = -inex_im; /* negate the ternary flag */ } return MPC_INEX(inex_re, inex_im); } prec = MPC_PREC_RE(rop); mpfr_init2 (w, 2); /* let op = x + iy; log = 1/2 log (x^2 + y^2) + i atan2 (y, x) */ /* loop for the real part: 1/2 log (x^2 + y^2), fast, but unsafe */ /* implementation */ ok = 0; for (loops = 1; !ok && loops <= 2; loops++) { prec += mpc_ceil_log2 (prec) + 4; mpfr_set_prec (w, prec); mpc_abs (w, op, GMP_RNDN); /* error 0.5 ulp */ if (mpfr_inf_p (w)) /* intermediate overflow; the logarithm may be representable. Intermediate underflow is impossible. */ break; mpfr_log (w, w, GMP_RNDN); /* generic error of log: (2^(- exp(w)) + 0.5) ulp */ if (mpfr_zero_p (w)) /* impossible to round, switch to second algorithm */ break; err = MPC_MAX (-mpfr_get_exp (w), 0) + 1; /* number of lost digits */ ok = mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ, mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN)); } if (!ok) { prec = MPC_PREC_RE(rop); mpfr_init2 (v, 2); /* compute 1/2 log (x^2 + y^2) = log |x| + 1/2 * log (1 + (y/x)^2) if |x| >= |y|; otherwise, exchange x and y */ if (mpfr_cmpabs (mpc_realref (op), mpc_imagref (op)) >= 0) { x = mpc_realref (op); y = mpc_imagref (op); } else { x = mpc_imagref (op); y = mpc_realref (op); } do { prec += mpc_ceil_log2 (prec) + 4; mpfr_set_prec (v, prec); mpfr_set_prec (w, prec); mpfr_div (v, y, x, GMP_RNDD); /* error 1 ulp */ mpfr_sqr (v, v, GMP_RNDD); /* generic error of multiplication: 1 + 2*1*(2+1*2^(1-prec)) <= 5.0625 since prec >= 6 */ mpfr_log1p (v, v, GMP_RNDD); /* error 1 + 4*5.0625 = 21.25 , see algorithms.tex */ mpfr_div_2ui (v, v, 1, GMP_RNDD); /* If the result is 0, then there has been an underflow somewhere. */ mpfr_abs (w, x, GMP_RNDN); /* exact */ mpfr_log (w, w, GMP_RNDN); /* error 0.5 ulp */ expw = mpfr_get_exp (w); sgnw = mpfr_signbit (w); mpfr_add (w, w, v, GMP_RNDN); if (!sgnw) /* v is positive, so no cancellation; error 22.25 ulp; error counts lost bits */ err = 5; else err = MPC_MAX (5 + mpfr_get_exp (v), /* 21.25 ulp (v) rewritten in ulp (result, now in w) */ -1 + expw - mpfr_get_exp (w) /* 0.5 ulp (previous w), rewritten in ulp (result) */ ) + 2; /* handle one special case: |x|=1, and (y/x)^2 underflows; then 1/2*log(x^2+y^2) \approx 1/2*y^2 also underflows. */ if ( (mpfr_cmp_si (x, -1) == 0 || mpfr_cmp_ui (x, 1) == 0) && mpfr_zero_p (w)) underflow = 1; } while (!underflow && !mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ, mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN))); mpfr_clear (v); } /* imaginary part */ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op), MPC_RND_IM (rnd)); /* set the real part; cannot be done before if rop==op */ if (underflow) /* create underflow in result */ inex_re = mpfr_set_ui_2exp (mpc_realref (rop), 1, mpfr_get_emin_min () - 2, MPC_RND_RE (rnd)); else inex_re = mpfr_set (mpc_realref (rop), w, MPC_RND_RE (rnd)); mpfr_clear (w); return MPC_INEX(inex_re, inex_im); }
mpcomplex mpcomplex::abs() const{ mpfr_t absoluteValue; mpfr_init2(absoluteValue, mpc_prec); mpc_abs(absoluteValue, mpc_val , default_rnd ); return mpcomplex( absoluteValue ); }