static void tgeneric_cci (mpc_function *function, mpc_ptr op1, int op2, mpc_ptr rop, mpc_ptr rop4, mpc_ptr rop4rnd, mpc_rnd_t rnd) { known_signs_t ks = {1, 1}; function->pointer.CCI (rop4, op1, op2, rnd); function->pointer.CCI (rop, op1, op2, rnd); if (MPFR_CAN_ROUND (mpc_realref (rop4), 1, MPC_PREC_RE (rop), MPC_RND_RE (rnd)) && MPFR_CAN_ROUND (mpc_imagref (rop4), 1, MPC_PREC_IM (rop), MPC_RND_IM (rnd))) mpc_set (rop4rnd, rop4, rnd); else return; if (same_mpc_value (rop, rop4rnd, ks)) return; printf ("Rounding in %s might be incorrect for\n", function->name); MPC_OUT (op1); printf ("op2=%d\n", op2); printf ("with rounding mode (%s, %s)", mpfr_print_rnd_mode (MPC_RND_RE (rnd)), mpfr_print_rnd_mode (MPC_RND_IM (rnd))); printf ("\n%s gives ", function->name); MPC_OUT (rop); printf ("%s quadruple precision gives ", function->name); MPC_OUT (rop4); printf ("and is rounded to "); MPC_OUT (rop4rnd); exit (1); }
int mpc_mul_i (mpc_ptr a, mpc_srcptr b, int sign, mpc_rnd_t rnd) /* if sign is >= 0, multiply by i, otherwise by -i */ { int inex_re, inex_im; mpfr_t tmp; /* Treat the most probable case of compatible precisions first */ if ( MPFR_PREC (MPC_RE (b)) == MPFR_PREC (MPC_IM (a)) && MPFR_PREC (MPC_IM (b)) == MPFR_PREC (MPC_RE (a))) { if (a == b) mpfr_swap (MPC_RE (a), MPC_IM (a)); else { mpfr_set (MPC_RE (a), MPC_IM (b), GMP_RNDN); mpfr_set (MPC_IM (a), MPC_RE (b), GMP_RNDN); } if (sign >= 0) MPFR_CHANGE_SIGN (MPC_RE (a)); else MPFR_CHANGE_SIGN (MPC_IM (a)); inex_re = 0; inex_im = 0; } else { if (a == b) { mpfr_init2 (tmp, MPFR_PREC (MPC_RE (a))); if (sign >= 0) { inex_re = mpfr_neg (tmp, MPC_IM (b), MPC_RND_RE (rnd)); inex_im = mpfr_set (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd)); } else { inex_re = mpfr_set (tmp, MPC_IM (b), MPC_RND_RE (rnd)); inex_im = mpfr_neg (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd)); } mpfr_clear (MPC_RE (a)); MPC_RE (a)[0] = tmp [0]; } else if (sign >= 0) { inex_re = mpfr_neg (MPC_RE (a), MPC_IM (b), MPC_RND_RE (rnd)); inex_im = mpfr_set (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd)); } else { inex_re = mpfr_set (MPC_RE (a), MPC_IM (b), MPC_RND_RE (rnd)); inex_im = mpfr_neg (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd)); } } return MPC_INEX(inex_re, inex_im); }
static void tgeneric_cc_c (mpc_function *function, mpc_ptr op, mpc_ptr rop1, mpc_ptr rop2, mpc_ptr rop14, mpc_ptr rop24, mpc_ptr rop14rnd, mpc_ptr rop24rnd, mpc_rnd_t rnd1, mpc_rnd_t rnd2) { /* same as the previous function, but for mpc functions computing two results from one argument */ known_signs_t ks = {1, 1}; function->pointer.CC_C (rop14, rop24, op, rnd1, rnd2); function->pointer.CC_C (rop1, rop2, op, rnd1, rnd2); if ( MPFR_CAN_ROUND (mpc_realref (rop14), 1, MPC_PREC_RE (rop1), MPC_RND_RE (rnd1)) && MPFR_CAN_ROUND (mpc_imagref (rop14), 1, MPC_PREC_IM (rop1), MPC_RND_IM (rnd1)) && MPFR_CAN_ROUND (mpc_realref (rop24), 1, MPC_PREC_RE (rop2), MPC_RND_RE (rnd2)) && MPFR_CAN_ROUND (mpc_imagref (rop24), 1, MPC_PREC_IM (rop2), MPC_RND_IM (rnd2))) { mpc_set (rop14rnd, rop14, rnd1); mpc_set (rop24rnd, rop24, rnd2); } else return; if (!same_mpc_value (rop1, rop14rnd, ks)) { /* rounding failed for first result */ printf ("Rounding might be incorrect for the first result of %s at\n", function->name); MPC_OUT (op); printf ("with rounding mode (%s, %s)", mpfr_print_rnd_mode (MPC_RND_RE (rnd1)), mpfr_print_rnd_mode (MPC_RND_IM (rnd1))); printf ("\n%s gives ", function->name); MPC_OUT (rop1); printf ("%s quadruple precision gives ", function->name); MPC_OUT (rop14); printf ("and is rounded to "); MPC_OUT (rop14rnd); exit (1); } else if (!same_mpc_value (rop2, rop24rnd, ks)) { /* rounding failed for second result */ printf ("Rounding might be incorrect for the second result of %s at\n", function->name); MPC_OUT (op); printf ("with rounding mode (%s, %s)", mpfr_print_rnd_mode (MPC_RND_RE (rnd2)), mpfr_print_rnd_mode (MPC_RND_IM (rnd2))); printf ("\n%s gives ", function->name); MPC_OUT (rop2); printf ("%s quadruple precision gives ", function->name); MPC_OUT (rop24); printf ("and is rounded to "); MPC_OUT (rop24rnd); exit (1); } }
int mpc_acosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) { /* acosh(z) = NaN + i*NaN, if z=0+i*NaN -i*acos(z), if sign(Im(z)) = - i*acos(z), if sign(Im(z)) = + http://functions.wolfram.com/ElementaryFunctions/ArcCosh/27/02/03/01/01/ */ mpc_t a; mpfr_t tmp; int inex; if (mpfr_zero_p (MPC_RE (op)) && mpfr_nan_p (MPC_IM (op))) { mpfr_set_nan (MPC_RE (rop)); mpfr_set_nan (MPC_IM (rop)); return 0; } /* Note reversal of precisions due to later multiplication by i or -i */ mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop)); if (mpfr_signbit (MPC_IM (op))) { inex = mpc_acos (a, op, RNDC (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd))); /* change a to -i*a, i.e., -y+i*x to x+i*y */ tmp[0] = MPC_RE (a)[0]; MPC_RE (a)[0] = MPC_IM (a)[0]; MPC_IM (a)[0] = tmp[0]; MPFR_CHANGE_SIGN (MPC_IM (a)); inex = MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex)); } else { inex = mpc_acos (a, op, RNDC (MPC_RND_IM (rnd), INV_RND(MPC_RND_RE (rnd)))); /* change a to i*a, i.e., y-i*x to x+i*y */ tmp[0] = MPC_RE (a)[0]; MPC_RE (a)[0] = MPC_IM (a)[0]; MPC_IM (a)[0] = tmp[0]; MPFR_CHANGE_SIGN (MPC_RE (a)); inex = MPC_INEX (-MPC_INEX_IM (inex), MPC_INEX_RE (inex)); } mpc_set (rop, a, rnd); mpc_clear (a); return inex; }
int mpc_tanh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) { /* tanh(op) = -i*tan(i*op) = conj(-i*tan(conj(-i*op))) */ mpc_t z; mpc_t tan_z; int inex; /* z := conj(-i * op) and rop = conj(-i * tan(z)), in other words, we have to switch real and imaginary parts. Let us set them without copying significands. */ mpc_realref (z)[0] = mpc_imagref (op)[0]; mpc_imagref (z)[0] = mpc_realref (op)[0]; mpc_realref (tan_z)[0] = mpc_imagref (rop)[0]; mpc_imagref (tan_z)[0] = mpc_realref (rop)[0]; inex = mpc_tan (tan_z, z, MPC_RND (MPC_RND_IM (rnd), MPC_RND_RE (rnd))); /* tan_z and rop parts share the same significands, copy the rest now. */ mpc_realref (rop)[0] = mpc_imagref (tan_z)[0]; mpc_imagref (rop)[0] = mpc_realref (tan_z)[0]; /* swap inexact flags for real and imaginary parts */ return MPC_INEX (MPC_INEX_IM (inex), MPC_INEX_RE (inex)); }
int mpc_asinh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) { /* asinh(op) = -i*asin(i*op) */ int inex; mpc_t z, a; mpfr_t tmp; /* z = i*op */ MPC_RE (z)[0] = MPC_IM (op)[0]; MPC_IM (z)[0] = MPC_RE (op)[0]; MPFR_CHANGE_SIGN (MPC_RE (z)); /* Note reversal of precisions due to later multiplication by -i */ mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop)); inex = mpc_asin (a, z, RNDC (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd))); /* if a = asin(i*op) = x+i*y, and we want y-i*x */ /* change a to -i*a */ tmp[0] = MPC_RE (a)[0]; MPC_RE (a)[0] = MPC_IM (a)[0]; MPC_IM (a)[0] = tmp[0]; MPFR_CHANGE_SIGN (MPC_IM (a)); mpc_set (rop, a, MPC_RNDNN); /* exact */ mpc_clear (a); return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex)); }
static int mpc_div_real (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd) /* Assumes z finite and w finite and non-zero, with imaginary part of w a signed zero. */ { int inex_re, inex_im; /* save signs of operands in case there are overlaps */ int zrs = MPFR_SIGNBIT (mpc_realref (z)); int zis = MPFR_SIGNBIT (mpc_imagref (z)); int wrs = MPFR_SIGNBIT (mpc_realref (w)); int wis = MPFR_SIGNBIT (mpc_imagref (w)); /* warning: rop may overlap with z,w so treat the imaginary part first */ inex_im = mpfr_div (mpc_imagref(rop), mpc_imagref(z), mpc_realref(w), MPC_RND_IM(rnd)); inex_re = mpfr_div (mpc_realref(rop), mpc_realref(z), mpc_realref(w), MPC_RND_RE(rnd)); /* correct signs of zeroes if necessary, which does not affect the inexact flags */ if (mpfr_zero_p (mpc_realref (rop))) mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis), MPFR_RNDN); /* exact */ if (mpfr_zero_p (mpc_imagref (rop))) mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis), MPFR_RNDN); return MPC_INEX(inex_re, inex_im); }
int mpc_atanh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) { /* atanh(op) = -i*atan(i*op) */ int inex; mpfr_t tmp; mpc_t z, a; MPC_RE (z)[0] = MPC_IM (op)[0]; MPC_IM (z)[0] = MPC_RE (op)[0]; MPFR_CHANGE_SIGN (MPC_RE (z)); /* Note reversal of precisions due to later multiplication by -i */ mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop)); inex = mpc_atan (a, z, RNDC (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd))); /* change a to -i*a, i.e., x+i*y to y-i*x */ tmp[0] = MPC_RE (a)[0]; MPC_RE (a)[0] = MPC_IM (a)[0]; MPC_IM (a)[0] = tmp[0]; MPFR_CHANGE_SIGN (MPC_IM (a)); mpc_set (rop, a, rnd); mpc_clear (a); return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex)); }
static PyObject * GMPy_PyStr_From_MPC(MPC_Object *self, int base, int digits, CTXT_Object *context) { PyObject *tempreal = 0, *tempimag = 0, *result; CHECK_CONTEXT(context); if (!((base >= 2) && (base <= 62))) { VALUE_ERROR("base must be in the interval [2,62]"); return NULL; } if ((digits < 0) || (digits == 1)) { VALUE_ERROR("digits must be 0 or >= 2"); return NULL; } tempreal = mpfr_ascii(mpc_realref(self->c), base, digits, MPC_RND_RE(GET_MPC_ROUND(context))); tempimag = mpfr_ascii(mpc_imagref(self->c), base, digits, MPC_RND_IM(GET_MPC_ROUND(context))); if (!tempreal || !tempimag) { Py_XDECREF(tempreal); Py_XDECREF(tempimag); return NULL; } result = Py_BuildValue("(NN)", tempreal, tempimag); if (!result) { Py_DECREF(tempreal); Py_DECREF(tempimag); } return result; }
char * mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd) { size_t needed_size; char *real_str; char *imag_str; char *complex_str = NULL; if (base < 2 || base > 36) return NULL; real_str = get_pretty_str (base, n, MPC_RE (op), MPC_RND_RE (rnd)); imag_str = get_pretty_str (base, n, MPC_IM (op), MPC_RND_IM (rnd)); needed_size = strlen (real_str) + strlen (imag_str) + 4; complex_str = mpc_alloc_str (needed_size); MPC_ASSERT (complex_str != NULL); strcpy (complex_str, "("); strcat (complex_str, real_str); strcat (complex_str, " "); strcat (complex_str, imag_str); strcat (complex_str, ")"); mpc_free_str (real_str); mpc_free_str (imag_str); return complex_str; }
/* res <- x[0]*y[0] + ... + x[n-1]*y[n-1] */ int mpc_dot (mpc_ptr res, const mpc_ptr *x, const mpc_ptr *y, unsigned long n, mpc_rnd_t rnd) { int inex_re, inex_im; mpfr_ptr *t; mpfr_t *z; unsigned long i; z = (mpfr_t *) malloc (2 * n * sizeof (mpfr_t)); MPC_ASSERT(z != NULL); t = (mpfr_ptr *) malloc (2 * n * sizeof(mpfr_ptr)); MPC_ASSERT(t != NULL); for (i = 0; i < 2 * n; i++) t[i] = z[i]; /* we first store in z[i] the value of Re(x[i])*Re(y[i]) and in z[n+i] that of -Im(x[i])*Im(y[i]) */ for (i = 0; i < n; i++) { mpfr_prec_t prec_x_re = mpfr_get_prec (mpc_realref (x[i])); mpfr_prec_t prec_x_im = mpfr_get_prec (mpc_imagref (x[i])); mpfr_prec_t prec_y_re = mpfr_get_prec (mpc_realref (y[i])); mpfr_prec_t prec_y_im = mpfr_get_prec (mpc_imagref (y[i])); mpfr_prec_t prec_y_max = MPC_MAX (prec_y_re, prec_y_im); /* we allocate z[i] with prec_x_re + prec_y_max bits so that the second loop below does not reallocate */ mpfr_init2 (z[i], prec_x_re + prec_y_max); mpfr_set_prec (z[i], prec_x_re + prec_y_re); mpfr_mul (z[i], mpc_realref (x[i]), mpc_realref (y[i]), MPFR_RNDZ); /* idem for z[n+i]: we allocate with prec_x_im + prec_y_max bits */ mpfr_init2 (z[n+i], prec_x_im + prec_y_max); mpfr_set_prec (z[n+i], prec_x_im + prec_y_im); mpfr_mul (z[n+i], mpc_imagref (x[i]), mpc_imagref (y[i]), MPFR_RNDZ); mpfr_neg (z[n+i], z[n+i], MPFR_RNDZ); } inex_re = mpfr_sum (mpc_realref (res), t, 2 * n, MPC_RND_RE (rnd)); /* we then store in z[i] the value of Re(x[i])*Im(y[i]) and in z[n+i] that of Im(x[i])*Re(y[i]) */ for (i = 0; i < n; i++) { mpfr_prec_t prec_x_re = mpfr_get_prec (mpc_realref (x[i])); mpfr_prec_t prec_x_im = mpfr_get_prec (mpc_imagref (x[i])); mpfr_prec_t prec_y_re = mpfr_get_prec (mpc_realref (y[i])); mpfr_prec_t prec_y_im = mpfr_get_prec (mpc_imagref (y[i])); mpfr_set_prec (z[i], prec_x_re + prec_y_im); mpfr_mul (z[i], mpc_realref (x[i]), mpc_imagref (y[i]), MPFR_RNDZ); mpfr_set_prec (z[n+i], prec_x_im + prec_y_re); mpfr_mul (z[n+i], mpc_imagref (x[i]), mpc_realref (y[i]), MPFR_RNDZ); } inex_im = mpfr_sum (mpc_imagref (res), t, 2 * n, MPC_RND_IM (rnd)); for (i = 0; i < 2 * n; i++) mpfr_clear (z[i]); free (t); free (z); return MPC_INEX(inex_re, inex_im); }
static int is_valid_mpc_rnd_mode (mpc_rnd_t rnd) /* returns 1 if curr is a valid rounding mode, and 0 otherwise */ { mpfr_rnd_t rnd_re = MPC_RND_RE (rnd); mpfr_rnd_t rnd_im = MPC_RND_IM (rnd); return is_valid_mpfr_rnd_mode (rnd_re) && is_valid_mpfr_rnd_mode (rnd_im); }
/* functions with one input, one output */ static void tgeneric_cc (mpc_function *function, mpc_ptr op, mpc_ptr rop, mpc_ptr rop4, mpc_ptr rop4rnd, mpc_rnd_t rnd) { known_signs_t ks = {1, 1}; /* We 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 (but we try to avoid them). */ function->pointer.CC (rop4, op, rnd); function->pointer.CC (rop, op, rnd); /* can't use the mpfr_can_round function when argument is singular, use a custom macro instead. */ if (MPFR_CAN_ROUND (mpc_realref (rop4), 1, MPC_PREC_RE (rop), MPC_RND_RE (rnd)) && MPFR_CAN_ROUND (mpc_imagref (rop4), 1, MPC_PREC_IM (rop), MPC_RND_IM (rnd))) mpc_set (rop4rnd, rop4, rnd); else /* avoid double rounding error */ return; if (same_mpc_value (rop, rop4rnd, ks)) return; /* rounding failed */ printf ("Rounding in %s might be incorrect for\n", function->name); MPC_OUT (op); printf ("with rounding mode (%s, %s)", mpfr_print_rnd_mode (MPC_RND_RE (rnd)), mpfr_print_rnd_mode (MPC_RND_IM (rnd))); printf ("\n%s gives ", function->name); MPC_OUT (rop); printf ("%s quadruple precision gives ", function->name); MPC_OUT (rop4); printf ("and is rounded to "); MPC_OUT (rop4rnd); exit (1); }
static int mpc_sin_cos_imag (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op, mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos) /* assumes that op is purely imaginary */ { int inex_sin_im = 0, inex_cos_re = 0; /* assume exact if not computed */ int overlap; mpc_t op_loc; overlap = (rop_sin == op || rop_cos == op); if (overlap) { mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op)); mpc_set (op_loc, op, MPC_RNDNN); } else op_loc [0] = op [0]; if (rop_sin != NULL) { /* sin(+-O +i*y) = +-0 +i*sinh(y) */ mpfr_set (MPC_RE(rop_sin), MPC_RE(op_loc), GMP_RNDN); inex_sin_im = mpfr_sinh (MPC_IM(rop_sin), MPC_IM(op_loc), MPC_RND_IM(rnd_sin)); } if (rop_cos != NULL) { /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0, cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0, where y >= 0 */ if (mpfr_zero_p (MPC_IM (op_loc))) inex_cos_re = mpfr_set_ui (MPC_RE (rop_cos), 1ul, MPC_RND_RE (rnd_cos)); else inex_cos_re = mpfr_cosh (MPC_RE (rop_cos), MPC_IM (op_loc), MPC_RND_RE (rnd_cos)); mpfr_set_ui (MPC_IM (rop_cos), 0ul, MPC_RND_IM (rnd_cos)); if (mpfr_signbit (MPC_RE (op_loc)) == mpfr_signbit (MPC_IM (op_loc))) MPFR_CHANGE_SIGN (MPC_IM (rop_cos)); } if (overlap) mpc_clear (op_loc); return MPC_INEX12 (MPC_INEX (0, inex_sin_im), MPC_INEX (inex_cos_re, 0)); }
/* return 0 iff both the real and imaginary parts are exact */ int mpc_add_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd) { int inex_re, inex_im; inex_re = mpfr_add (MPC_RE(a), MPC_RE(b), c, MPC_RND_RE(rnd)); inex_im = mpfr_set (MPC_IM(a), MPC_IM(b), MPC_RND_IM(rnd)); return MPC_INEX(inex_re, inex_im); }