/// @brief sin keyword implementation /// void program::rpn_sin(void) { MIN_ARGUMENTS(1); if (_stack->get_type(0) == cmd_number) { floating_t* left = &((number*)_stack->get_obj(0))->_value; CHECK_MPFR(mpfr_sin(left->mpfr, left->mpfr, floating_t::s_mpfr_rnd)); } else if (_stack->get_type(0) == cmd_complex) { // sin(x+iy)=sin(x)cosh(y)+icos(x)sinh(y) stack::copy_and_push_back(*_stack, _stack->size() - 1, _calc_stack); floating_t* tmp = &((number*)_calc_stack.allocate_back(number::calc_size(), cmd_number))->_value; floating_t* x = ((complex*)_calc_stack.get_obj(1))->re(); floating_t* y = ((complex*)_calc_stack.get_obj(1))->im(); floating_t* re = ((complex*)_stack->get_obj(0))->re(); floating_t* im = ((complex*)_stack->get_obj(0))->im(); CHECK_MPFR(mpfr_sin(re->mpfr, x->mpfr, floating_t::s_mpfr_rnd)); CHECK_MPFR(mpfr_cosh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd)); CHECK_MPFR(mpfr_mul(re->mpfr, re->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd)); CHECK_MPFR(mpfr_cos(im->mpfr, x->mpfr, floating_t::s_mpfr_rnd)); CHECK_MPFR(mpfr_sinh(tmp->mpfr, y->mpfr, floating_t::s_mpfr_rnd)); CHECK_MPFR(mpfr_mul(im->mpfr, im->mpfr, tmp->mpfr, floating_t::s_mpfr_rnd)); _calc_stack.pop_back(2); } else ERR_CONTEXT(ret_bad_operand_type); }
int main (int argc, char *argv[]) { mpfr_t x; #ifdef HAVE_INFS check53 (DBL_NAN, DBL_NAN, GMP_RNDN); check53 (DBL_POS_INF, DBL_NAN, GMP_RNDN); check53 (DBL_NEG_INF, DBL_NAN, GMP_RNDN); #endif /* worst case from PhD thesis of Vincent Lefe`vre: x=8980155785351021/2^54 */ check53 (4.984987858808754279e-1, 4.781075595393330379e-1, GMP_RNDN); check53 (4.984987858808754279e-1, 4.781075595393329824e-1, GMP_RNDD); check53 (4.984987858808754279e-1, 4.781075595393329824e-1, GMP_RNDZ); check53 (4.984987858808754279e-1, 4.781075595393330379e-1, GMP_RNDU); check53 (1.00031274099908640274, 8.416399183372403892e-1, GMP_RNDN); check53 (1.00229256850978698523, 8.427074524447979442e-1, GMP_RNDZ); check53 (1.00288304857059840103, 8.430252033025980029e-1, GMP_RNDZ); check53 (1.00591265847407274059, 8.446508805292128885e-1, GMP_RNDN); check53 (1.00591265847407274059, 8.446508805292128885e-1, GMP_RNDN); mpfr_init2 (x, 2); mpfr_set_d (x, 0.5, GMP_RNDN); mpfr_sin (x, x, GMP_RNDD); if (mpfr_get_d1 (x) != 0.375) { fprintf (stderr, "mpfr_sin(0.5, GMP_RNDD) failed with precision=2\n"); exit (1); } /* bug found by Kevin Ryde */ mpfr_const_pi (x, GMP_RNDN); mpfr_mul_ui (x, x, 3L, GMP_RNDN); mpfr_div_ui (x, x, 2L, GMP_RNDN); mpfr_sin (x, x, GMP_RNDN); if (mpfr_cmp_ui (x, 0) >= 0) { fprintf (stderr, "Error: wrong sign for sin(3*Pi/2)\n"); exit (1); } mpfr_clear (x); test_generic (2, 100, 80); return 0; }
REAL _sin(REAL a, REAL, QByteArray &) { // qDebug() << "aaaa:" << getQString(a); mpfr_t tmp1; mpfr_init2(tmp1, NUMBITS); mpfr_t result; mpfr_init2(result, NUMBITS); try { // mpfr_init_set_f(tmp1, a.get_mpf_t(), MPFR_RNDN); mpfr_set_str(tmp1, getString(a).data(), 10, MPFR_RNDN); // char *s; // mp_exp_t e; // s = mpfr_get_str(NULL, &e, 10, 510, tmp1, MPFR_RNDN); // qDebug() << "aaaa:" << getQString(a) << " " << s; // a = "0.0"; // mpfr_get_f(a.get_mpf_t(), tmp1, MPFR_RNDN); // qDebug() << "aaaa:" << getQString(a); mpfr_sin(result, tmp1, MPFR_RNDN); mpfr_get_f(a.get_mpf_t(), result, MPFR_RNDN); } catch(...) { mpfr_clear(tmp1); mpfr_clear(result); return ZERO; } mpfr_clear(tmp1); mpfr_clear(result); return a; }
real sin(const real & a) { real x; mpfr_sin(x.r, a.r, MPFR_RNDN); return x; }
static PyObject * GMPy_Complex_Rect(PyObject *x, PyObject *y, CTXT_Object *context) { MPFR_Object *tempx, *tempy; MPC_Object *result; CHECK_CONTEXT(context); tempx = GMPy_MPFR_From_Real(x, 1, context); tempy = GMPy_MPFR_From_Real(y, 1, context); result = GMPy_MPC_New(0, 0, context); if (!tempx || !tempy || !result) { Py_XDECREF((PyObject*)tempx); Py_XDECREF((PyObject*)tempy); Py_XDECREF((PyObject*)result); return NULL; } mpfr_cos(mpc_realref(result->c), tempy->f, GET_REAL_ROUND(context)); mpfr_mul(mpc_realref(result->c), mpc_realref(result->c), tempx->f, GET_REAL_ROUND(context)); mpfr_sin(mpc_imagref(result->c), tempy->f, GET_IMAG_ROUND(context)); mpfr_mul(mpc_imagref(result->c), mpc_imagref(result->c), tempx->f, GET_IMAG_ROUND(context)); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); GMPY_MPC_CLEANUP(result, context, "rect()"); return (PyObject*)result; }
static int mpc_sin_cos_real (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 real */ { int inex_sin_re = 0, inex_cos_re = 0; /* Until further notice, assume computations exact; in particular, by definition, for not computed values. */ mpfr_t s, c; int inex_s, inex_c; int sign_im_op = mpfr_signbit (MPC_IM (op)); /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */ /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */ if (rop_sin != 0) mpfr_init2 (s, MPC_PREC_RE (rop_sin)); else mpfr_init2 (s, 2); /* We need only the sign. */ if (rop_cos != NULL) mpfr_init2 (c, MPC_PREC_RE (rop_cos)); else mpfr_init2 (c, 2); inex_s = mpfr_sin (s, MPC_RE (op), MPC_RND_RE (rnd_sin)); inex_c = mpfr_cos (c, MPC_RE (op), MPC_RND_RE (rnd_cos)); /* We cannot use mpfr_sin_cos since we may need two distinct rounding modes and the exact return values. If we need only the sign, an arbitrary rounding mode will work. */ if (rop_sin != NULL) { mpfr_set (MPC_RE (rop_sin), s, GMP_RNDN); /* exact */ inex_sin_re = inex_s; mpfr_set_ui (MPC_IM (rop_sin), 0ul, GMP_RNDN); if ( ( sign_im_op && !mpfr_signbit (c)) || (!sign_im_op && mpfr_signbit (c))) MPFR_CHANGE_SIGN (MPC_IM (rop_sin)); /* FIXME: simpler implementation with mpfr-3: mpfr_set_zero (MPC_IM (rop_sin), ( ( mpfr_signbit (MPC_IM(op)) && !mpfr_signbit(c)) || (!mpfr_signbit (MPC_IM(op)) && mpfr_signbit(c)) ? -1 : 1); there is no need to use the variable sign_im_op then, needed now in the case rop_sin == op */ } if (rop_cos != NULL) { mpfr_set (MPC_RE (rop_cos), c, GMP_RNDN); /* exact */ inex_cos_re = inex_c; mpfr_set_ui (MPC_IM (rop_cos), 0ul, GMP_RNDN); if ( ( sign_im_op && mpfr_signbit (s)) || (!sign_im_op && !mpfr_signbit (s))) MPFR_CHANGE_SIGN (MPC_IM (rop_cos)); /* FIXME: see previous MPFR_CHANGE_SIGN */ } mpfr_clear (s); mpfr_clear (c); return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0)); }
/* Test provided by Christopher Creutzig, 2007-05-21. */ static void check_tiny (void) { mpfr_t x, y; mpfr_init2 (x, 53); mpfr_init2 (y, 53); mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_set_exp (x, mpfr_get_emin ()); mpfr_sin (y, x, MPFR_RNDD); if (mpfr_cmp (x, y) < 0) { printf ("Error in check_tiny: got sin(x) > x for x = 2^(emin-1)\n"); exit (1); } mpfr_sin (y, x, MPFR_RNDU); mpfr_mul_2ui (y, y, 1, MPFR_RNDU); if (mpfr_cmp (x, y) > 0) { printf ("Error in check_tiny: got sin(x) < x/2 for x = 2^(emin-1)\n"); exit (1); } mpfr_neg (x, x, MPFR_RNDN); mpfr_sin (y, x, MPFR_RNDU); if (mpfr_cmp (x, y) > 0) { printf ("Error in check_tiny: got sin(x) < x for x = -2^(emin-1)\n"); exit (1); } mpfr_sin (y, x, MPFR_RNDD); mpfr_mul_2ui (y, y, 1, MPFR_RNDD); if (mpfr_cmp (x, y) < 0) { printf ("Error in check_tiny: got sin(x) > x/2 for x = -2^(emin-1)\n"); exit (1); } mpfr_clear (y); mpfr_clear (x); }
decimal r_sin(const decimal& a,bool round) { #ifdef USE_CGAL CGAL::Gmpfr m; CGAL::Gmpfr n=to_gmpfr(a); mpfr_sin(m.fr(),n.fr(),MPFR_RNDN); return r_round_preference(decimal(m),round); #else return r_round_preference(sin(a),round); #endif }
int main (void) { mpfr_t x; mp_set_memory_functions (my_alloc1, my_realloc1, my_free1); mpfr_init2 (x, 53); mpfr_set_ui (x, I, MPFR_RNDN); mpfr_sin (x, x, MPFR_RNDN); mpfr_clear (x); mp_set_memory_functions (my_alloc2, my_realloc2, my_free2); mpfr_init2 (x, 1000); mpfr_set_ui (x, I, MPFR_RNDN); mpfr_sin (x, x, MPFR_RNDN); mpfr_clear (x); return 0; }
static int mpc_sin_cos_real (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 real */ { int inex_sin_re = 0, inex_cos_re = 0; /* Until further notice, assume computations exact; in particular, by definition, for not computed values. */ mpfr_t s, c; int inex_s, inex_c; int sign_im = mpfr_signbit (mpc_imagref (op)); /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */ /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */ if (rop_sin != 0) mpfr_init2 (s, MPC_PREC_RE (rop_sin)); else mpfr_init2 (s, 2); /* We need only the sign. */ if (rop_cos != NULL) mpfr_init2 (c, MPC_PREC_RE (rop_cos)); else mpfr_init2 (c, 2); inex_s = mpfr_sin (s, mpc_realref (op), MPC_RND_RE (rnd_sin)); inex_c = mpfr_cos (c, mpc_realref (op), MPC_RND_RE (rnd_cos)); /* We cannot use mpfr_sin_cos since we may need two distinct rounding modes and the exact return values. If we need only the sign, an arbitrary rounding mode will work. */ if (rop_sin != NULL) { mpfr_set (mpc_realref (rop_sin), s, MPFR_RNDN); /* exact */ inex_sin_re = inex_s; mpfr_set_zero (mpc_imagref (rop_sin), ( ( sign_im && !mpfr_signbit(c)) || (!sign_im && mpfr_signbit(c)) ? -1 : 1)); } if (rop_cos != NULL) { mpfr_set (mpc_realref (rop_cos), c, MPFR_RNDN); /* exact */ inex_cos_re = inex_c; mpfr_set_zero (mpc_imagref (rop_cos), ( ( sign_im && mpfr_signbit(s)) || (!sign_im && !mpfr_signbit(s)) ? -1 : 1)); } mpfr_clear (s); mpfr_clear (c); return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0)); }
/* bug reported by Eric Veach */ static void bug20090519 (void) { mpfr_t x, y, r; int inexact; mpfr_inits2 (100, x, y, r, (mpfr_ptr) 0); mpfr_set_prec (x, 3); mpfr_set_prec (y, 3); mpfr_set_prec (r, 3); mpfr_set_si (x, 8, MPFR_RNDN); mpfr_set_si (y, 7, MPFR_RNDN); check (r, x, y, MPFR_RNDN); mpfr_set_prec (x, 10); mpfr_set_prec (y, 10); mpfr_set_prec (r, 10); mpfr_set_ui_2exp (x, 3, 26, MPFR_RNDN); mpfr_set_si (y, (1 << 9) - 1, MPFR_RNDN); check (r, x, y, MPFR_RNDN); mpfr_set_prec (x, 100); mpfr_set_prec (y, 100); mpfr_set_prec (r, 100); mpfr_set_str (x, "3.5", 10, MPFR_RNDN); mpfr_set_str (y, "1.1", 10, MPFR_RNDN); check (r, x, y, MPFR_RNDN); /* double check, with a pre-computed value */ { mpfr_t er; mpfr_init2 (er, 100); mpfr_set_str (er, "CCCCCCCCCCCCCCCCCCCCCCCC8p-102", 16, MPFR_RNDN); inexact = mpfr_fmod (r, x, y, MPFR_RNDN); if (!mpfr_equal_p (r, er) || inexact != 0) test_failed (er, r, 0, inexact, x, y, MPFR_RNDN); mpfr_clear (er); } mpfr_set_si (x, 20, MPFR_RNDN); mpfr_set_ui_2exp (y, 1, 1, MPFR_RNDN); /* exact */ mpfr_sin (y, y, MPFR_RNDN); check (r, x, y, MPFR_RNDN); mpfr_clears(r, x, y, (mpfr_ptr) 0); }
void fmpq_poly_sample_D1(fmpq_poly_t f, int n, mpfr_prec_t prec, gmp_randstate_t state) { mpfr_t u1; mpfr_init2(u1, prec); mpfr_t u2; mpfr_init2(u2, prec); mpfr_t z1; mpfr_init2(z1, prec); mpfr_t z2; mpfr_init2(z2, prec); mpfr_t pi2; mpfr_init2(pi2, prec); mpfr_const_pi(pi2, MPFR_RNDN); mpfr_mul_si(pi2, pi2, 2, MPFR_RNDN); mpf_t tmp_f; mpq_t tmp_q; mpf_init(tmp_f); mpq_init(tmp_q); assert(n%2==0); for(long i=0; i<n; i+=2) { mpfr_urandomb(u1, state); mpfr_urandomb(u2, state); mpfr_log(u1, u1, MPFR_RNDN); mpfr_mul_si(u1, u1, -2, MPFR_RNDN); mpfr_sqrt(u1, u1, MPFR_RNDN); mpfr_mul(u2, pi2, u2, MPFR_RNDN); mpfr_cos(z1, u2, MPFR_RNDN); mpfr_mul(z1, z1, u1, MPFR_RNDN); //z1 = sqrt(-2*log(u1)) * cos(2*pi*u2) mpfr_sin(z2, u2, MPFR_RNDN); mpfr_mul(z2, z2, u1, MPFR_RNDN); //z1 = sqrt(-2*log(u1)) * sin(2*pi*U2) mpfr_get_f(tmp_f, z1, MPFR_RNDN); mpq_set_f(tmp_q, tmp_f); fmpq_poly_set_coeff_mpq(f, i, tmp_q); mpfr_get_f(tmp_f, z2, MPFR_RNDN); mpq_set_f(tmp_q, tmp_f); fmpq_poly_set_coeff_mpq(f, i+1, tmp_q); } mpf_clear(tmp_f); mpq_clear(tmp_q); mpfr_clear(pi2); mpfr_clear(u1); mpfr_clear(u2); mpfr_clear(z1); mpfr_clear(z2); }
static int test_sin (mpfr_ptr a, mpfr_srcptr b, mpfr_rnd_t rnd_mode) { int res; int ok = rnd_mode == MPFR_RNDN && mpfr_number_p (b) && mpfr_get_prec (a)>=53; if (ok) { mpfr_print_raw (b); } res = mpfr_sin (a, b, rnd_mode); if (ok) { printf (" "); mpfr_print_raw (a); printf ("\n"); } return res; }
//------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_float::sin() { #ifdef KNUMBER_USE_MPFR mpfr_t mpfr; mpfr_init_set_f(mpfr, mpf_, rounding_mode); mpfr_sin(mpfr, mpfr, rounding_mode); mpfr_get_f(mpf_, mpfr, rounding_mode); mpfr_clear(mpfr); return this; #else const double x = mpf_get_d(mpf_); if(isinf(x)) { delete this; return new knumber_error(knumber_error::ERROR_POS_INFINITY); } else { return execute_libc_func< ::sin>(x); } #endif }
void check53 (double x, double sin_x, mp_rnd_t rnd_mode) { mpfr_t xx, s; mpfr_init2 (xx, 53); mpfr_init2 (s, 53); mpfr_set_d (xx, x, rnd_mode); /* should be exact */ mpfr_sin (s, xx, rnd_mode); if (mpfr_get_d1 (s) != sin_x && (!isnan(sin_x) || !mpfr_nan_p(s))) { fprintf (stderr, "mpfr_sin failed for x=%1.20e, rnd=%s\n", x, mpfr_print_rnd_mode (rnd_mode)); fprintf (stderr, "mpfr_sin gives sin(x)=%1.20e, expected %1.20e\n", mpfr_get_d1 (s), sin_x); exit(1); } mpfr_clear (xx); mpfr_clear (s); }
/* Bug reported by Laurent Fousse for the 2.4 branch. No problem in the trunk. https://sympa.inria.fr/sympa/arc/mpfr/2009-11/msg00044.html */ static void bug20091122 (void) { mpfr_t x, y, z, yref, zref; mpfr_prec_t p = 3; mpfr_rnd_t r = MPFR_RNDN; mpfr_init2 (x, 5); mpfr_init2 (y, p); mpfr_init2 (z, p); mpfr_init2 (yref, p); mpfr_init2 (zref, p); mpfr_set_str (x, "0.11111E49", 2, MPFR_RNDN); mpfr_sin_cos (yref, zref, x, r); mpfr_sin (y, x, r); mpfr_cos (z, x, r); if (! mpfr_equal_p (y, yref)) { printf ("mpfr_sin_cos and mpfr_sin disagree (bug20091122)\n"); printf ("yref = "); mpfr_dump (yref); printf ("y = "); mpfr_dump (y); exit (1); } if (! mpfr_equal_p (z, zref)) { printf ("mpfr_sin_cos and mpfr_cos disagree (bug20091122)\n"); printf ("zref = "); mpfr_dump (zref); printf ("z = "); mpfr_dump (z); exit (1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); mpfr_clear (yref); mpfr_clear (zref); }
static void check_regression (void) { mpfr_t x, y; mpfr_prec_t p; int i; p = strlen (xs) - 2 - 3; mpfr_inits2 (p, x, y, (mpfr_ptr) 0); mpfr_set_str (x, xs, 2, MPFR_RNDN); i = mpfr_sin (y, x, MPFR_RNDN); if (i >= 0 || mpfr_cmp_str (y, "0.111001110011110011110001010110011101110E-1", 2, MPFR_RNDN)) { printf ("Regression test failed (1) i=%d\ny=", i); mpfr_dump (y); exit (1); } mpfr_clears (x, y, (mpfr_ptr) 0); }
int main (int argc, char *argv[]) { int n, prec, st, st2, N, i; mpfr_t x, y, z; if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: timing digits \n"); exit(1); } printf ("Using MPFR-%s with GMP-%s\n", mpfr_version, gmp_version); n = atoi(argv[1]); prec = (int) ( n * log(10.0) / log(2.0) + 1.0 ); printf("[precision is %u bits]\n", prec); mpfr_init2(x, prec); mpfr_init2(y, prec); mpfr_init2(z, prec); mpfr_set_d(x, 3.0, GMP_RNDN); mpfr_sqrt(x, x, GMP_RNDN); mpfr_sub_ui (x, x, 1, GMP_RNDN); mpfr_set_d(y, 5.0, GMP_RNDN); mpfr_sqrt(y, y, GMP_RNDN); mpfr_log (z, x, GMP_RNDN); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_mul(z, x, y, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("x*y took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_mul(z, x, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("x*x took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_div(z, x, y, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("x/y took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_sqrt(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("sqrt(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_exp(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("exp(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_log(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("log(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_sin(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("sin(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_cos(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("cos(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_acos(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("arccos(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); N=1; st = cputime(); do { for (i=0;i<N;i++) mpfr_atan(z, x, GMP_RNDN); N=2*N; st2=cputime(); } while (st2-st<1000); printf("arctan(x) took %f ms (%d eval in %d ms)\n", (double)(st2-st)/(N-1),N-1,st2-st); mpfr_clear(x); mpfr_clear(y); mpfr_clear(z); return 0; }
int main (int argc, char *argv[]) { mpfr_t x, c, s, c2, s2; tests_start_mpfr (); check_regression (); check_nans (); /* worst case from PhD thesis of Vincent Lefe`vre: x=8980155785351021/2^54 */ check53 ("4.984987858808754279e-1", "4.781075595393330379e-1", MPFR_RNDN); check53 ("4.984987858808754279e-1", "4.781075595393329824e-1", MPFR_RNDD); check53 ("4.984987858808754279e-1", "4.781075595393329824e-1", MPFR_RNDZ); check53 ("4.984987858808754279e-1", "4.781075595393330379e-1", MPFR_RNDU); check53 ("1.00031274099908640274", "8.416399183372403892e-1", MPFR_RNDN); check53 ("1.00229256850978698523", "8.427074524447979442e-1", MPFR_RNDZ); check53 ("1.00288304857059840103", "8.430252033025980029e-1", MPFR_RNDZ); check53 ("1.00591265847407274059", "8.446508805292128885e-1", MPFR_RNDN); /* Other worst cases showing a bug introduced on 2005-01-29 in rev 3248 */ check53b ("1.0111001111010111010111111000010011010001110001111011e-21", "1.0111001111010111010111111000010011010001101001110001e-21", MPFR_RNDU); check53b ("1.1011101111111010000001010111000010000111100100101101", "1.1111100100101100001111100000110011110011010001010101e-1", MPFR_RNDU); mpfr_init2 (x, 2); mpfr_set_str (x, "0.5", 10, MPFR_RNDN); test_sin (x, x, MPFR_RNDD); if (mpfr_cmp_ui_2exp (x, 3, -3)) /* x != 0.375 = 3/8 */ { printf ("mpfr_sin(0.5, MPFR_RNDD) failed with precision=2\n"); exit (1); } /* bug found by Kevin Ryde */ mpfr_const_pi (x, MPFR_RNDN); mpfr_mul_ui (x, x, 3L, MPFR_RNDN); mpfr_div_ui (x, x, 2L, MPFR_RNDN); test_sin (x, x, MPFR_RNDN); if (mpfr_cmp_ui (x, 0) >= 0) { printf ("Error: wrong sign for sin(3*Pi/2)\n"); exit (1); } /* Can fail on an assert */ mpfr_set_prec (x, 53); mpfr_set_str (x, "77291789194529019661184401408", 10, MPFR_RNDN); mpfr_init2 (c, 4); mpfr_init2 (s, 42); mpfr_init2 (c2, 4); mpfr_init2 (s2, 42); test_sin (s, x, MPFR_RNDN); mpfr_cos (c, x, MPFR_RNDN); mpfr_sin_cos (s2, c2, x, MPFR_RNDN); if (mpfr_cmp (c2, c)) { printf("cos differs for x=77291789194529019661184401408"); exit (1); } if (mpfr_cmp (s2, s)) { printf("sin differs for x=77291789194529019661184401408"); exit (1); } mpfr_set_str_binary (x, "1.1001001000011111101101010100010001000010110100010011"); test_sin (x, x, MPFR_RNDZ); if (mpfr_cmp_str (x, "1.1111111111111111111111111111111111111111111111111111e-1", 2, MPFR_RNDN)) { printf ("Error for x= 1.1001001000011111101101010100010001000010110100010011\nGot "); mpfr_dump (x); exit (1); } mpfr_set_prec (s, 9); mpfr_set_prec (x, 190); mpfr_const_pi (x, MPFR_RNDN); mpfr_sin (s, x, MPFR_RNDZ); if (mpfr_cmp_str (s, "0.100000101e-196", 2, MPFR_RNDN)) { printf ("Error for x ~= pi\n"); mpfr_dump (s); exit (1); } mpfr_clear (s2); mpfr_clear (c2); mpfr_clear (s); mpfr_clear (c); mpfr_clear (x); test_generic (2, 100, 15); test_generic (MPFR_SINCOS_THRESHOLD-1, MPFR_SINCOS_THRESHOLD+1, 2); test_sign (); check_tiny (); data_check ("data/sin", mpfr_sin, "mpfr_sin"); bad_cases (mpfr_sin, mpfr_asin, "mpfr_sin", 256, -40, 0, 4, 128, 800, 50); tests_end_mpfr (); return 0; }
/* return in z a lower bound (for rnd = RNDD) or upper bound (for rnd = RNDU) of |zeta(s)|/2, using: log(|zeta(s)|/2) = (s-1)*log(2*Pi) + lngamma(1-s) + log(|sin(Pi*s/2)| * zeta(1-s)). Assumes s < 1/2 and s1 = 1-s exactly, thus s1 > 1/2. y and p are temporary variables. At input, p is Pi rounded down. The comments in the code are for rnd = RNDD. */ static void mpfr_reflection_overflow (mpfr_t z, mpfr_t s1, const mpfr_t s, mpfr_t y, mpfr_t p, mpfr_rnd_t rnd) { mpz_t sint; MPFR_ASSERTD (rnd == MPFR_RNDD || rnd == MPFR_RNDU); /* Since log is increasing, we want lower bounds on |sin(Pi*s/2)| and zeta(1-s). */ mpz_init (sint); mpfr_get_z (sint, s, MPFR_RNDD); /* sint = floor(s) */ /* We first compute a lower bound of |sin(Pi*s/2)|, which is a periodic function of period 2. Thus: if 2k < s < 2k+1, then |sin(Pi*s/2)| is increasing; if 2k-1 < s < 2k, then |sin(Pi*s/2)| is decreasing. These cases are distinguished by testing bit 0 of floor(s) as if represented in two's complement (or equivalently, as an unsigned integer mod 2): 0: sint = 0 mod 2, thus 2k < s < 2k+1 and |sin(Pi*s/2)| is increasing; 1: sint = 1 mod 2, thus 2k-1 < s < 2k and |sin(Pi*s/2)| is decreasing. Let's recall that the comments are for rnd = RNDD. */ if (mpz_tstbit (sint, 0) == 0) /* |sin(Pi*s/2)| is increasing: round down Pi*s to get a lower bound. */ { mpfr_mul (y, p, s, rnd); if (rnd == MPFR_RNDD) mpfr_nextabove (p); /* we will need p rounded above afterwards */ } else /* |sin(Pi*s/2)| is decreasing: round up Pi*s to get a lower bound. */ { if (rnd == MPFR_RNDD) mpfr_nextabove (p); mpfr_mul (y, p, s, MPFR_INVERT_RND(rnd)); } mpfr_div_2ui (y, y, 1, MPFR_RNDN); /* exact, rounding mode doesn't matter */ /* The rounding direction of sin depends on its sign. We have: if -4k-2 < s < -4k, then -2k-1 < s/2 < -2k, thus sin(Pi*s/2) < 0; if -4k < s < -4k+2, then -2k < s/2 < -2k+1, thus sin(Pi*s/2) > 0. These cases are distinguished by testing bit 1 of floor(s) as if represented in two's complement (or equivalently, as an unsigned integer mod 4): 0: sint = {0,1} mod 4, thus -2k < s/2 < -2k+1 and sin(Pi*s/2) > 0; 1: sint = {2,3} mod 4, thus -2k-1 < s/2 < -2k and sin(Pi*s/2) < 0. Let's recall that the comments are for rnd = RNDD. */ if (mpz_tstbit (sint, 1) == 0) /* -2k < s/2 < -2k+1; sin(Pi*s/2) > 0 */ { /* Round sin down to get a lower bound of |sin(Pi*s/2)|. */ mpfr_sin (y, y, rnd); } else /* -2k-1 < s/2 < -2k; sin(Pi*s/2) < 0 */ { /* Round sin up to get a lower bound of |sin(Pi*s/2)|. */ mpfr_sin (y, y, MPFR_INVERT_RND(rnd)); mpfr_abs (y, y, MPFR_RNDN); /* exact, rounding mode doesn't matter */ } mpz_clear (sint); /* now y <= |sin(Pi*s/2)| when rnd=RNDD, y >= |sin(Pi*s/2)| when rnd=RNDU */ mpfr_zeta_pos (z, s1, rnd); /* zeta(1-s) */ mpfr_mul (z, z, y, rnd); /* now z <= |sin(Pi*s/2)|*zeta(1-s) */ mpfr_log (z, z, rnd); /* now z <= log(|sin(Pi*s/2)|*zeta(1-s)) */ mpfr_lngamma (y, s1, rnd); mpfr_add (z, z, y, rnd); /* z <= lngamma(1-s) + log(|sin(Pi*s/2)|*zeta(1-s)) */ /* since s-1 < 0, we want to round log(2*pi) upwards */ mpfr_mul_2ui (y, p, 1, MPFR_INVERT_RND(rnd)); mpfr_log (y, y, MPFR_INVERT_RND(rnd)); mpfr_mul (y, y, s1, MPFR_INVERT_RND(rnd)); mpfr_sub (z, z, y, rnd); mpfr_exp (z, z, rnd); if (rnd == MPFR_RNDD) mpfr_nextbelow (p); /* restore original p */ }
int mpfr_zeta (mpfr_t z, mpfr_srcptr s, mp_rnd_t rnd_mode) { mpfr_t z_pre, s1, y, p; double sd, eps, m1, c; long add; mp_prec_t precz, prec1, precs, precs1; int inex; MPFR_GROUP_DECL (group); MPFR_ZIV_DECL (loop); MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("s[%#R]=%R rnd=%d", s, s, rnd_mode), ("z[%#R]=%R inexact=%d", z, z, inex)); /* Zero, Nan or Inf ? */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (s))) { if (MPFR_IS_NAN (s)) { MPFR_SET_NAN (z); MPFR_RET_NAN; } else if (MPFR_IS_INF (s)) { if (MPFR_IS_POS (s)) return mpfr_set_ui (z, 1, GMP_RNDN); /* Zeta(+Inf) = 1 */ MPFR_SET_NAN (z); /* Zeta(-Inf) = NaN */ MPFR_RET_NAN; } else /* s iz zero */ { MPFR_ASSERTD (MPFR_IS_ZERO (s)); mpfr_set_ui (z, 1, rnd_mode); mpfr_div_2ui (z, z, 1, rnd_mode); MPFR_CHANGE_SIGN (z); MPFR_RET (0); } } /* s is neither Nan, nor Inf, nor Zero */ /* check tiny s: we have zeta(s) = -1/2 - 1/2 log(2 Pi) s + ... around s=0, and for |s| <= 0.074, we have |zeta(s) + 1/2| <= |s|. Thus if |s| <= 1/4*ulp(1/2), we can deduce the correct rounding (the 1/4 covers the case where |zeta(s)| < 1/2 and rounding to nearest). A sufficient condition is that EXP(s) + 1 < -PREC(z). */ if (MPFR_EXP(s) + 1 < - (mp_exp_t) MPFR_PREC(z)) { int signs = MPFR_SIGN(s); mpfr_set_si_2exp (z, -1, -1, rnd_mode); /* -1/2 */ if ((rnd_mode == GMP_RNDU || rnd_mode == GMP_RNDZ) && signs < 0) { mpfr_nextabove (z); /* z = -1/2 + epsilon */ inex = 1; } else if (rnd_mode == GMP_RNDD && signs > 0) { mpfr_nextbelow (z); /* z = -1/2 - epsilon */ inex = -1; } else { if (rnd_mode == GMP_RNDU) /* s > 0: z = -1/2 */ inex = 1; else if (rnd_mode == GMP_RNDD) inex = -1; /* s < 0: z = -1/2 */ else /* (GMP_RNDZ and s > 0) or GMP_RNDN: z = -1/2 */ inex = (signs > 0) ? 1 : -1; } return mpfr_check_range (z, inex, rnd_mode); } /* Check for case s= -2n */ if (MPFR_IS_NEG (s)) { mpfr_t tmp; tmp[0] = *s; MPFR_EXP (tmp) = MPFR_EXP (s) - 1; if (mpfr_integer_p (tmp)) { MPFR_SET_ZERO (z); MPFR_SET_POS (z); MPFR_RET (0); } } MPFR_SAVE_EXPO_MARK (expo); /* Compute Zeta */ if (MPFR_IS_POS (s) && MPFR_GET_EXP (s) >= 0) /* Case s >= 1/2 */ inex = mpfr_zeta_pos (z, s, rnd_mode); else /* use reflection formula zeta(s) = 2^s*Pi^(s-1)*sin(Pi*s/2)*gamma(1-s)*zeta(1-s) */ { precz = MPFR_PREC (z); precs = MPFR_PREC (s); /* Precision precs1 needed to represent 1 - s, and s + 2, without any truncation */ precs1 = precs + 2 + MAX (0, - MPFR_GET_EXP (s)); sd = mpfr_get_d (s, GMP_RNDN) - 1.0; if (sd < 0.0) sd = -sd; /* now sd = abs(s-1.0) */ /* Precision prec1 is the precision on elementary computations; it ensures a final precision prec1 - add for zeta(s) */ /* eps = pow (2.0, - (double) precz - 14.0); */ eps = __gmpfr_ceil_exp2 (- (double) precz - 14.0); m1 = 1.0 + MAX(1.0 / eps, 2.0 * sd) * (1.0 + eps); c = (1.0 + eps) * (1.0 + eps * MAX(8.0, m1)); /* add = 1 + floor(log(c*c*c*(13 + m1))/log(2)); */ add = __gmpfr_ceil_log2 (c * c * c * (13.0 + m1)); prec1 = precz + add; prec1 = MAX (prec1, precs1) + 10; MPFR_GROUP_INIT_4 (group, prec1, z_pre, s1, y, p); MPFR_ZIV_INIT (loop, prec1); for (;;) { mpfr_sub (s1, __gmpfr_one, s, GMP_RNDN);/* s1 = 1-s */ mpfr_zeta_pos (z_pre, s1, GMP_RNDN); /* zeta(1-s) */ mpfr_gamma (y, s1, GMP_RNDN); /* gamma(1-s) */ if (MPFR_IS_INF (y)) /* Zeta(s) < 0 for -4k-2 < s < -4k, Zeta(s) > 0 for -4k < s < -4k+2 */ { MPFR_SET_INF (z_pre); mpfr_div_2ui (s1, s, 2, GMP_RNDN); /* s/4, exact */ mpfr_frac (s1, s1, GMP_RNDN); /* exact, -1 < s1 < 0 */ if (mpfr_cmp_si_2exp (s1, -1, -1) > 0) MPFR_SET_NEG (z_pre); else MPFR_SET_POS (z_pre); break; } mpfr_mul (z_pre, z_pre, y, GMP_RNDN); /* gamma(1-s)*zeta(1-s) */ mpfr_const_pi (p, GMP_RNDD); mpfr_mul (y, s, p, GMP_RNDN); mpfr_div_2ui (y, y, 1, GMP_RNDN); /* s*Pi/2 */ mpfr_sin (y, y, GMP_RNDN); /* sin(Pi*s/2) */ mpfr_mul (z_pre, z_pre, y, GMP_RNDN); mpfr_mul_2ui (y, p, 1, GMP_RNDN); /* 2*Pi */ mpfr_neg (s1, s1, GMP_RNDN); /* s-1 */ mpfr_pow (y, y, s1, GMP_RNDN); /* (2*Pi)^(s-1) */ mpfr_mul (z_pre, z_pre, y, GMP_RNDN); mpfr_mul_2ui (z_pre, z_pre, 1, GMP_RNDN); if (MPFR_LIKELY (MPFR_CAN_ROUND (z_pre, prec1 - add, precz, rnd_mode))) break; MPFR_ZIV_NEXT (loop, prec1); MPFR_GROUP_REPREC_4 (group, prec1, z_pre, s1, y, p); } MPFR_ZIV_FREE (loop); inex = mpfr_set (z, z_pre, rnd_mode); MPFR_GROUP_CLEAR (group); } MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (z, inex, rnd_mode); }
/* 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); }
static void consistency (void) { mpfr_t x, s1, s2, c1, c2; mpfr_exp_t emin, emax; mpfr_rnd_t rnd; unsigned int flags_sin, flags_cos, flags, flags_before, flags_ref; int inex_sin, is, inex_cos, ic, inex, inex_ref; int i; emin = mpfr_get_emin (); emax = mpfr_get_emax (); for (i = 0; i <= 10000; i++) { mpfr_init2 (x, MPFR_PREC_MIN + (randlimb () % 8)); mpfr_inits2 (MPFR_PREC_MIN + (randlimb () % 8), s1, s2, c1, c2, (mpfr_ptr) 0); if (i < 8 * MPFR_RND_MAX) { int j = i / MPFR_RND_MAX; if (j & 1) mpfr_set_emin (MPFR_EMIN_MIN); mpfr_set_si (x, (j & 2) ? 1 : -1, MPFR_RNDN); mpfr_set_exp (x, mpfr_get_emin ()); rnd = (mpfr_rnd_t) (i % MPFR_RND_MAX); flags_before = 0; if (j & 4) mpfr_set_emax (-17); } else { tests_default_random (x, 256, -5, 50, 0); rnd = RND_RAND (); flags_before = (randlimb () & 1) ? (unsigned int) (MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE) : (unsigned int) 0; } __gmpfr_flags = flags_before; inex_sin = mpfr_sin (s1, x, rnd); is = inex_sin < 0 ? 2 : inex_sin > 0 ? 1 : 0; flags_sin = __gmpfr_flags; __gmpfr_flags = flags_before; inex_cos = mpfr_cos (c1, x, rnd); ic = inex_cos < 0 ? 2 : inex_cos > 0 ? 1 : 0; flags_cos = __gmpfr_flags; __gmpfr_flags = flags_before; inex = mpfr_sin_cos (s2, c2, x, rnd); flags = __gmpfr_flags; inex_ref = is + 4 * ic; flags_ref = flags_sin | flags_cos; if (!(mpfr_equal_p (s1, s2) && mpfr_equal_p (c1, c2)) || inex != inex_ref || flags != flags_ref) { printf ("mpfr_sin_cos and mpfr_sin/mpfr_cos disagree on %s," " i = %d\nx = ", mpfr_print_rnd_mode (rnd), i); mpfr_dump (x); printf ("s1 = "); mpfr_dump (s1); printf ("s2 = "); mpfr_dump (s2); printf ("c1 = "); mpfr_dump (c1); printf ("c2 = "); mpfr_dump (c2); printf ("inex_sin = %d (s = %d), inex_cos = %d (c = %d), " "inex = %d (expected %d)\n", inex_sin, is, inex_cos, ic, inex, inex_ref); printf ("flags_sin = 0x%x, flags_cos = 0x%x, " "flags = 0x%x (expected 0x%x)\n", flags_sin, flags_cos, flags, flags_ref); exit (1); } mpfr_clears (x, s1, s2, c1, c2, (mpfr_ptr) 0); mpfr_set_emin (emin); mpfr_set_emax (emax); } }
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { double *prec,*eoutr,*eouti; int mrows,ncols; char *input_buf; char *w1,*w2; int buflen,status; mpfr_t xr,xi,yr,yi,zr,zi,temp,temp1,temp2,temp3,temp4; mp_exp_t expptr; /* Check for proper number of arguments. */ if(nrhs!=5) { mexErrMsgTxt("5 inputs required."); } else if(nlhs>4) { mexErrMsgTxt("Too many output arguments"); } /* The input must be a noncomplex scalar double.*/ mrows = mxGetM(prhs[0]); ncols = mxGetN(prhs[0]); if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || !(mrows==1 && ncols==1) ) { mexErrMsgTxt("Input must be a noncomplex scalar double."); } /* Set precision and initialize mpfr variables */ prec = mxGetPr(prhs[0]); mpfr_set_default_prec(*prec); mpfr_init(xr); mpfr_init(xi); mpfr_init(yr); mpfr_init(yi); mpfr_init(zr); mpfr_init(zi); mpfr_init(temp); mpfr_init(temp1); mpfr_init(temp2); mpfr_init(temp3); mpfr_init(temp4); /* Read the input strings into mpfr x real */ buflen = (mxGetM(prhs[1]) * mxGetN(prhs[1])) + 1; input_buf=mxCalloc(buflen, sizeof(char)); status = mxGetString(prhs[1], input_buf, buflen); mpfr_set_str(xr,input_buf,10,GMP_RNDN); /* Read the input strings into mpfr x imag */ buflen = (mxGetM(prhs[2]) * mxGetN(prhs[2])) + 1; input_buf=mxCalloc(buflen, sizeof(char)); status = mxGetString(prhs[2], input_buf, buflen); mpfr_set_str(xi,input_buf,10,GMP_RNDN); /* Read the input strings into mpfr y real */ buflen = (mxGetM(prhs[3]) * mxGetN(prhs[3])) + 1; input_buf=mxCalloc(buflen, sizeof(char)); status = mxGetString(prhs[3], input_buf, buflen); mpfr_set_str(yr,input_buf,10,GMP_RNDN); /* Read the input strings into mpfr y imag */ buflen = (mxGetM(prhs[4]) * mxGetN(prhs[4])) + 1; input_buf=mxCalloc(buflen, sizeof(char)); status = mxGetString(prhs[4], input_buf, buflen); mpfr_set_str(yi,input_buf,10,GMP_RNDN); /* Mathematical operation */ /* ln(magnitude) */ mpfr_mul(temp,xr,xr,GMP_RNDN); mpfr_mul(temp1,xi,xi,GMP_RNDN); mpfr_add(temp,temp,temp1,GMP_RNDN); mpfr_sqrt(temp,temp,GMP_RNDN); mpfr_log(temp,temp,GMP_RNDN); /* angle */ mpfr_atan2(temp1,xi,xr,GMP_RNDN); /* real exp */ mpfr_mul(temp3,temp,yr,GMP_RNDN); mpfr_mul(temp2,temp1,yi,GMP_RNDN); mpfr_sub(temp3,temp3,temp2,GMP_RNDN); mpfr_exp(temp3,temp3,GMP_RNDN); /* cos sin argument */ mpfr_mul(temp2,temp1,yr,GMP_RNDN); mpfr_mul(temp4,temp,yi,GMP_RNDN); mpfr_add(temp2,temp2,temp4,GMP_RNDN); mpfr_cos(zr,temp2,GMP_RNDN); mpfr_mul(zr,zr,temp3,GMP_RNDN); mpfr_sin(zi,temp2,GMP_RNDN); mpfr_mul(zi,zi,temp3,GMP_RNDN); /* Retrieve results */ mxFree(input_buf); input_buf=mpfr_get_str (NULL, &expptr, 10, 0, zr, GMP_RNDN); w1=malloc(strlen(input_buf)+20); w2=malloc(strlen(input_buf)+20); if (strncmp(input_buf, "-", 1)==0){ strcpy(w2,&input_buf[1]); sprintf(w1,"-.%se%i",w2,expptr); } else { strcpy(w2,&input_buf[0]); sprintf(w1,"+.%se%i",w2,expptr); } plhs[0] = mxCreateString(w1); /* plhs[1] = mxCreateDoubleMatrix(mrows,ncols, mxREAL); */ /* eoutr=mxGetPr(plhs[1]); */ /* *eoutr=expptr; */ mpfr_free_str(input_buf); input_buf=mpfr_get_str (NULL, &expptr, 10, 0, zi, GMP_RNDN); free(w1); free(w2); w1=malloc(strlen(input_buf)+20); w2=malloc(strlen(input_buf)+20); if (strncmp(input_buf, "-", 1)==0){ strcpy(w2,&input_buf[1]); sprintf(w1,"-.%se%i",w2,expptr); } else { strcpy(w2,&input_buf[0]); sprintf(w1,"+.%se%i",w2,expptr); } plhs[1] = mxCreateString(w1); /* plhs[3] = mxCreateDoubleMatrix(mrows,ncols, mxREAL); */ /* eouti=mxGetPr(plhs[3]); */ /* *eouti=expptr; */ mpfr_clear(xr); mpfr_clear(xi); mpfr_clear(yr); mpfr_clear(yi); mpfr_clear(zr); mpfr_clear(zi); mpfr_clear(temp); mpfr_clear(temp1); mpfr_clear(temp2); mpfr_clear(temp3); mpfr_clear(temp4); mpfr_free_str(input_buf); free(w1); free(w2); }
MpfrFloat MpfrFloat::sin(const MpfrFloat& value) { MpfrFloat retval(MpfrFloat::kNoInitialization); mpfr_sin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); return retval; }
int mpfi_sin (mpfi_ptr a, mpfi_srcptr b) { int inexact_left, inexact_right, inexact = 0; mp_prec_t prec, prec_left, prec_right; mpfr_t tmp; mpz_t z, zmod4; mpz_t quad_left, quad_right; int ql_mod4, qr_mod4; if (MPFI_NAN_P (b)) { mpfr_set_nan (&(a->left)); mpfr_set_nan (&(a->right)); MPFR_RET_NAN; } if (MPFI_INF_P (b)) { /* the two endpoints are the same infinite */ if ( mpfr_cmp (&(b->left), &(b->right)) == 0) { mpfr_set_nan (&(a->left)); mpfr_set_nan (&(a->right)); MPFR_RET_NAN; } mpfr_set_si (&(a->left), -1, MPFI_RNDD); mpfr_set_si (&(a->right), 1, MPFI_RNDU); return 0; } mpz_init (quad_left); mpz_init (quad_right); mpz_init (z); /* quad_left gives the quadrant where the left endpoint of b is */ /* quad_left = floor (2 b->left / pi) */ /* idem for quad_right and b->right */ prec_left = mpfi_quadrant (quad_left, &(b->left)); prec_right = mpfi_quadrant (quad_right, &(b->right)); /* if there is at least one period in b, then a = [-1, 1] */ mpz_sub (z, quad_right, quad_left); if (mpz_cmp_ui (z, 4) >= 0) { mpfr_set_si (&(a->left), -1, MPFI_RNDD); mpfr_set_si (&(a->right), 1, MPFI_RNDU); inexact = 0; } else { /* there is less than one period in b */ /* let us discuss according to the position (quadrant) of the endpoints of b */ /* computing precision = maximal precision required to determine the */ /* relative position of the endpoints of b and of integer multiples of Pi / 2 */ prec = mpfi_get_prec (a); if (prec_left > prec) prec = prec_left; if (prec_right > prec) prec = prec_right; mpz_add (z, quad_left, quad_right); /* z = quad_right + quad_left */ mpz_init (zmod4); /* qr_mod4 gives the quadrant where the right endpoint of b is */ /* qr_mod4 = floor (2 b->right / pi) mod 4 */ mpz_mod_ui (zmod4, quad_right, 4); qr_mod4 = mpz_get_ui (zmod4); /* quad_left gives the quadrant where the left endpoint of b is */ /* quad_left = floor (2 b->left / pi) mod 4 */ mpz_mod_ui (zmod4, quad_left, 4); ql_mod4 = mpz_get_ui (zmod4); switch (qr_mod4) { case 0: switch (ql_mod4) { case 0: case 3: inexact_left = mpfr_sin (&(a->left), &(b->left), MPFI_RNDD); inexact_right = mpfr_sin (&(a->right), &(b->right), MPFI_RNDU); break; case 1: mpz_add_ui (z, z, 1); if (mpfi_cmp_sym_pi (z, &(b->left), &(b->right), prec) >= 0) inexact_right = mpfr_sin (&(a->right), &(b->left), MPFI_RNDU); else inexact_right = mpfr_sin (&(a->right), &(b->right), MPFI_RNDU); inexact_left = mpfr_set_si (&(a->left), -1, MPFI_RNDD); break; case 2: inexact_left = mpfr_set_si (&(a->left), -1, MPFI_RNDD); inexact_right = mpfr_sin (&(a->right), &(b->right), MPFI_RNDU); break; } break; case 1: switch (ql_mod4) { case 0: mpz_add_ui (z, z, 1); if (mpfi_cmp_sym_pi (z, &(b->right), &(b->left), prec) >= 0) inexact_left = mpfr_sin (&(a->left), &(b->left), MPFI_RNDD); else inexact_left = mpfr_sin (&(a->left), &(b->right), MPFI_RNDD); inexact_right = mpfr_set_si (&(a->right), 1, MPFI_RNDU); break; case 1: mpfr_init2 (tmp, mpfr_get_prec (&(a->left))); inexact_left = mpfr_sin (tmp, &(b->right), MPFI_RNDD); inexact_right = mpfr_sin (&(a->right), &(b->left), MPFI_RNDU); mpfr_set (&(a->left), tmp, MPFI_RNDD); /* exact */ mpfr_clear (tmp); break; case 2: inexact_left = mpfr_set_si (&(a->left), -1, MPFI_RNDD); inexact_right = mpfr_set_si (&(a->right), 1, MPFI_RNDU); break; case 3: inexact_left = mpfr_sin (&(a->left), &(b->left), MPFI_RNDD); inexact_right = mpfr_set_si (&(a->right), 1, MPFI_RNDU); break; } break; case 2: switch (ql_mod4) { case 0: inexact_left = mpfr_sin (&(a->left), &(b->right), MPFI_RNDD); inexact_right = mpfr_set_si (&(a->right), 1, MPFI_RNDU); break; case 1: case 2: mpfr_init2 (tmp, mpfr_get_prec (&(a->left))); inexact_left = mpfr_sin (tmp, &(b->right), MPFI_RNDD); inexact_right = mpfr_sin (&(a->right), &(b->left), MPFI_RNDU); mpfr_set (&(a->left), tmp, MPFI_RNDD); /* exact */ mpfr_clear (tmp); break; case 3: mpz_add_ui (z, z, 1); if (mpfi_cmp_sym_pi (z, &(b->left), &(b->right), prec) >= 0) inexact_left = mpfr_sin (&(a->left), &(b->left), MPFI_RNDD); else inexact_left = mpfr_sin (&(a->left), &(b->right), MPFI_RNDD); inexact_right = mpfr_set_si (&(a->right), 1, MPFI_RNDU); break; } break; case 3: switch (ql_mod4) { case 0: inexact_left = mpfr_set_si (&(a->left), -1, MPFI_RNDD); inexact_right = mpfr_set_si (&(a->right), 1, MPFI_RNDU); break; case 1: inexact_right = mpfr_sin (&(a->right), &(b->left), MPFI_RNDU); inexact_left = mpfr_set_si (&(a->left), -1, MPFI_RNDD); break; case 2: mpz_add_ui (z, z, 1); if (mpfi_cmp_sym_pi (z, &(b->right), &(b->left), prec) >= 0) inexact_right = mpfr_sin (&(a->right), &(b->left), MPFI_RNDU); else inexact_right = mpfr_sin (&(a->right), &(b->right), MPFI_RNDU); inexact_left = mpfr_set_si (&(a->left), -1, MPFI_RNDD); break; case 3: inexact_left = mpfr_sin (&(a->left), &(b->left), MPFI_RNDD); inexact_right = mpfr_sin (&(a->right), &(b->right), MPFI_RNDU); break; } break; } if (inexact_left) inexact = 1; if (inexact_right) inexact += 2; mpz_clear (zmod4); } mpz_clear (quad_left); mpz_clear (quad_right); mpz_clear (z); return inexact; }
void bvisit(const Sin &x) { apply(result_, *(x.get_arg())); mpfr_sin(result_, result_, rnd_); }
int main() { slong iter; flint_rand_t state; flint_printf("sin...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) { arb_t a, b; fmpq_t q; mpfr_t t; slong prec0, prec; prec0 = 400; if (iter % 100 == 0) prec0 = 8000; prec = 2 + n_randint(state, prec0); arb_init(a); arb_init(b); fmpq_init(q); mpfr_init2(t, prec0 + 100); arb_randtest(a, state, 1 + n_randint(state, prec0), 6); arb_randtest(b, state, 1 + n_randint(state, prec0), 6); arb_get_rand_fmpq(q, state, a, 1 + n_randint(state, prec0)); fmpq_get_mpfr(t, q, MPFR_RNDN); mpfr_sin(t, t, MPFR_RNDN); arb_sin(b, a, prec); if (!arb_contains_mpfr(b, t)) { flint_printf("FAIL: containment\n\n"); flint_printf("a = "); arb_print(a); flint_printf("\n\n"); flint_printf("b = "); arb_print(b); flint_printf("\n\n"); abort(); } arb_sin(a, a, prec); if (!arb_equal(a, b)) { flint_printf("FAIL: aliasing\n\n"); abort(); } arb_clear(a); arb_clear(b); fmpq_clear(q); mpfr_clear(t); } /* check large arguments */ for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) { arb_t a, b, c, d; slong prec0, prec1, prec2; if (iter % 10 == 0) prec0 = 10000; else prec0 = 1000; prec1 = 2 + n_randint(state, prec0); prec2 = 2 + n_randint(state, prec0); arb_init(a); arb_init(b); arb_init(c); arb_init(d); arb_randtest_special(a, state, 1 + n_randint(state, prec0), prec0); arb_randtest_special(b, state, 1 + n_randint(state, prec0), 100); arb_randtest_special(c, state, 1 + n_randint(state, prec0), 100); arb_randtest_special(d, state, 1 + n_randint(state, prec0), 100); arb_sin(b, a, prec1); arb_sin(c, a, prec2); if (!arb_overlaps(b, c)) { flint_printf("FAIL: overlap\n\n"); flint_printf("a = "); arb_print(a); flint_printf("\n\n"); flint_printf("b = "); arb_print(b); flint_printf("\n\n"); flint_printf("c = "); arb_print(c); flint_printf("\n\n"); abort(); } /* check sin(2a) = 2sin(a)cos(a) */ arb_mul_2exp_si(c, a, 1); arb_sin(c, c, prec1); arb_cos(d, a, prec1); arb_mul(b, b, d, prec1); arb_mul_2exp_si(b, b, 1); if (!arb_overlaps(b, c)) { flint_printf("FAIL: functional equation\n\n"); flint_printf("a = "); arb_print(a); flint_printf("\n\n"); flint_printf("b = "); arb_print(b); flint_printf("\n\n"); flint_printf("c = "); arb_print(c); flint_printf("\n\n"); abort(); } arb_clear(a); arb_clear(b); arb_clear(c); arb_clear(d); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
int mpfr_zeta (mpfr_t z, mpfr_srcptr s, mpfr_rnd_t rnd_mode) { mpfr_t z_pre, s1, y, p; long add; mpfr_prec_t precz, prec1, precs, precs1; int inex; MPFR_GROUP_DECL (group); MPFR_ZIV_DECL (loop); MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC ( ("s[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (s), mpfr_log_prec, s, rnd_mode), ("z[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (z), mpfr_log_prec, z, inex)); /* Zero, Nan or Inf ? */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (s))) { if (MPFR_IS_NAN (s)) { MPFR_SET_NAN (z); MPFR_RET_NAN; } else if (MPFR_IS_INF (s)) { if (MPFR_IS_POS (s)) return mpfr_set_ui (z, 1, MPFR_RNDN); /* Zeta(+Inf) = 1 */ MPFR_SET_NAN (z); /* Zeta(-Inf) = NaN */ MPFR_RET_NAN; } else /* s iz zero */ { MPFR_ASSERTD (MPFR_IS_ZERO (s)); return mpfr_set_si_2exp (z, -1, -1, rnd_mode); } } /* s is neither Nan, nor Inf, nor Zero */ /* check tiny s: we have zeta(s) = -1/2 - 1/2 log(2 Pi) s + ... around s=0, and for |s| <= 2^(-4), we have |zeta(s) + 1/2| <= |s|. EXP(s) + 1 < -PREC(z) is a sufficient condition to be able to round correctly, for any PREC(z) >= 1 (see algorithms.tex for details). */ if (MPFR_GET_EXP (s) + 1 < - (mpfr_exp_t) MPFR_PREC(z)) { int signs = MPFR_SIGN(s); MPFR_SAVE_EXPO_MARK (expo); mpfr_set_si_2exp (z, -1, -1, rnd_mode); /* -1/2 */ if (rnd_mode == MPFR_RNDA) rnd_mode = MPFR_RNDD; /* the result is around -1/2, thus negative */ if ((rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDZ) && signs < 0) { mpfr_nextabove (z); /* z = -1/2 + epsilon */ inex = 1; } else if (rnd_mode == MPFR_RNDD && signs > 0) { mpfr_nextbelow (z); /* z = -1/2 - epsilon */ inex = -1; } else { if (rnd_mode == MPFR_RNDU) /* s > 0: z = -1/2 */ inex = 1; else if (rnd_mode == MPFR_RNDD) inex = -1; /* s < 0: z = -1/2 */ else /* (MPFR_RNDZ and s > 0) or MPFR_RNDN: z = -1/2 */ inex = (signs > 0) ? 1 : -1; } MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (z, inex, rnd_mode); } /* Check for case s= -2n */ if (MPFR_IS_NEG (s)) { mpfr_t tmp; tmp[0] = *s; MPFR_EXP (tmp) = MPFR_GET_EXP (s) - 1; if (mpfr_integer_p (tmp)) { MPFR_SET_ZERO (z); MPFR_SET_POS (z); MPFR_RET (0); } } /* Check for case s=1 before changing the exponent range */ if (mpfr_cmp (s, __gmpfr_one) == 0) { MPFR_SET_INF (z); MPFR_SET_POS (z); MPFR_SET_DIVBY0 (); MPFR_RET (0); } MPFR_SAVE_EXPO_MARK (expo); /* Compute Zeta */ if (MPFR_IS_POS (s) && MPFR_GET_EXP (s) >= 0) /* Case s >= 1/2 */ inex = mpfr_zeta_pos (z, s, rnd_mode); else /* use reflection formula zeta(s) = 2^s*Pi^(s-1)*sin(Pi*s/2)*gamma(1-s)*zeta(1-s) */ { int overflow = 0; precz = MPFR_PREC (z); precs = MPFR_PREC (s); /* Precision precs1 needed to represent 1 - s, and s + 2, without any truncation */ precs1 = precs + 2 + MAX (0, - MPFR_GET_EXP (s)); /* Precision prec1 is the precision on elementary computations; it ensures a final precision prec1 - add for zeta(s) */ add = compute_add (s, precz); prec1 = precz + add; /* FIXME: To avoid that the working precision (prec1) depends on the input precision, one would need to take into account the error made when s1 is not exactly 1-s when computing zeta(s1) and gamma(s1) below, and also in the case y=Inf (i.e. when gamma(s1) overflows). Make sure that underflows do not occur in intermediate computations. Due to the limited precision, they are probably not possible in practice; add some MPFR_ASSERTN's to be sure that problems do not remain undetected? */ prec1 = MAX (prec1, precs1) + 10; MPFR_GROUP_INIT_4 (group, prec1, z_pre, s1, y, p); MPFR_ZIV_INIT (loop, prec1); for (;;) { mpfr_exp_t ey; mpfr_t z_up; mpfr_const_pi (p, MPFR_RNDD); /* p is Pi */ mpfr_sub (s1, __gmpfr_one, s, MPFR_RNDN); /* s1 = 1-s */ mpfr_gamma (y, s1, MPFR_RNDN); /* gamma(1-s) */ if (MPFR_IS_INF (y)) /* zeta(s) < 0 for -4k-2 < s < -4k, zeta(s) > 0 for -4k < s < -4k+2 */ { /* FIXME: An overflow in gamma(s1) does not imply that zeta(s) will overflow. A solution: 1. Compute log(|zeta(s)|/2) = (s-1)*log(2*pi) + lngamma(1-s) + log(abs(sin(Pi*s/2)) * zeta(1-s)) (possibly sharing computations with the normal case) with a rather good accuracy (see (2)). Memorize the sign of sin(...) for the final sign. 2. Take the exponential, ~= |zeta(s)|/2. If there is an overflow, then this means an overflow on the final result (due to the multiplication by 2, which has not been done yet). 3. Ziv test. 4. Correct the sign from the sign of sin(...). 5. Round then multiply by 2. Here, an overflow in either operation means a real overflow. */ mpfr_reflection_overflow (z_pre, s1, s, y, p, MPFR_RNDD); /* z_pre is a lower bound of |zeta(s)|/2, thus if it overflows, or has exponent emax, then |zeta(s)| overflows too. */ if (MPFR_IS_INF (z_pre) || MPFR_GET_EXP(z_pre) == __gmpfr_emax) { /* determine the sign of overflow */ mpfr_div_2ui (s1, s, 2, MPFR_RNDN); /* s/4, exact */ mpfr_frac (s1, s1, MPFR_RNDN); /* exact, -1 < s1 < 0 */ overflow = (mpfr_cmp_si_2exp (s1, -1, -1) > 0) ? -1 : 1; break; } else /* EXP(z_pre) < __gmpfr_emax */ { int ok = 0; mpfr_t z_down; mpfr_init2 (z_up, mpfr_get_prec (z_pre)); mpfr_reflection_overflow (z_up, s1, s, y, p, MPFR_RNDU); /* if the lower approximation z_pre does not overflow, but z_up does, we need more precision */ if (MPFR_IS_INF (z_up) || MPFR_GET_EXP(z_up) == __gmpfr_emax) goto next_loop; /* check if z_pre and z_up round to the same number */ mpfr_init2 (z_down, precz); mpfr_set (z_down, z_pre, rnd_mode); /* Note: it might be that EXP(z_down) = emax here, in that case we will have overflow below when we multiply by 2 */ mpfr_prec_round (z_up, precz, rnd_mode); ok = mpfr_cmp (z_down, z_up) == 0; mpfr_clear (z_up); mpfr_clear (z_down); if (ok) { /* get correct sign and multiply by 2 */ mpfr_div_2ui (s1, s, 2, MPFR_RNDN); /* s/4, exact */ mpfr_frac (s1, s1, MPFR_RNDN); /* exact, -1 < s1 < 0 */ if (mpfr_cmp_si_2exp (s1, -1, -1) > 0) mpfr_neg (z_pre, z_pre, rnd_mode); mpfr_mul_2ui (z_pre, z_pre, 1, rnd_mode); break; } else goto next_loop; } } mpfr_zeta_pos (z_pre, s1, MPFR_RNDN); /* zeta(1-s) */ mpfr_mul (z_pre, z_pre, y, MPFR_RNDN); /* gamma(1-s)*zeta(1-s) */ /* multiply z_pre by 2^s*Pi^(s-1) where p=Pi, s1=1-s */ mpfr_mul_2ui (y, p, 1, MPFR_RNDN); /* 2*Pi */ mpfr_neg (s1, s1, MPFR_RNDN); /* s-1 */ mpfr_pow (y, y, s1, MPFR_RNDN); /* (2*Pi)^(s-1) */ mpfr_mul (z_pre, z_pre, y, MPFR_RNDN); mpfr_mul_2ui (z_pre, z_pre, 1, MPFR_RNDN); /* multiply z_pre by sin(Pi*s/2) */ mpfr_mul (y, s, p, MPFR_RNDN); mpfr_div_2ui (p, y, 1, MPFR_RNDN); /* p = s*Pi/2 */ /* FIXME: sinpi will be available, we should replace the mpfr_sin call below by mpfr_sinpi(s/2), where s/2 will be exact. Can mpfr_sin underflow? Moreover, the code below should be improved so that the "if" condition becomes unlikely, e.g. by taking a slightly larger working precision. */ mpfr_sin (y, p, MPFR_RNDN); /* y = sin(Pi*s/2) */ ey = MPFR_GET_EXP (y); if (ey < 0) /* take account of cancellation in sin(p) */ { mpfr_t t; MPFR_ASSERTN (- ey < MPFR_PREC_MAX - prec1); mpfr_init2 (t, prec1 - ey); mpfr_const_pi (t, MPFR_RNDD); mpfr_mul (t, s, t, MPFR_RNDN); mpfr_div_2ui (t, t, 1, MPFR_RNDN); mpfr_sin (y, t, MPFR_RNDN); mpfr_clear (t); } mpfr_mul (z_pre, z_pre, y, MPFR_RNDN); if (MPFR_LIKELY (MPFR_CAN_ROUND (z_pre, prec1 - add, precz, rnd_mode))) break; next_loop: MPFR_ZIV_NEXT (loop, prec1); MPFR_GROUP_REPREC_4 (group, prec1, z_pre, s1, y, p); } MPFR_ZIV_FREE (loop); if (overflow != 0) { inex = mpfr_overflow (z, rnd_mode, overflow); MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_OVERFLOW); } else inex = mpfr_set (z, z_pre, rnd_mode); MPFR_GROUP_CLEAR (group); } MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (z, inex, rnd_mode); }
int mpc_exp (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) { mpfr_t x, y, z; mpfr_prec_t prec; int ok = 0; int inex_re, inex_im; int saved_underflow, saved_overflow; /* special values */ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op))) /* NaNs exp(nan +i*y) = nan -i*0 if y = -0, nan +i*0 if y = +0, nan +i*nan otherwise exp(x+i*nan) = +/-0 +/-i*0 if x=-inf, +/-inf +i*nan if x=+inf, nan +i*nan otherwise */ { if (mpfr_zero_p (mpc_imagref (op))) return mpc_set (rop, op, MPC_RNDNN); if (mpfr_inf_p (mpc_realref (op))) { if (mpfr_signbit (mpc_realref (op))) return mpc_set_ui_ui (rop, 0, 0, MPC_RNDNN); else { mpfr_set_inf (mpc_realref (rop), +1); mpfr_set_nan (mpc_imagref (rop)); return MPC_INEX(0, 0); /* Inf/NaN are exact */ } } mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); return MPC_INEX(0, 0); /* NaN is exact */ } if (mpfr_zero_p (mpc_imagref(op))) /* special case when the input is real exp(x-i*0) = exp(x) -i*0, even if x is NaN exp(x+i*0) = exp(x) +i*0, even if x is NaN */ { inex_re = mpfr_exp (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd)); inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref(op), MPC_RND_IM(rnd)); return MPC_INEX(inex_re, inex_im); } if (mpfr_zero_p (mpc_realref (op))) /* special case when the input is imaginary */ { inex_re = mpfr_cos (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE(rnd)); inex_im = mpfr_sin (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM(rnd)); return MPC_INEX(inex_re, inex_im); } if (mpfr_inf_p (mpc_realref (op))) /* real part is an infinity, exp(-inf +i*y) = 0*(cos y +i*sin y) exp(+inf +i*y) = +/-inf +i*nan if y = +/-inf +inf*(cos y +i*sin y) if 0 < |y| < inf */ { mpfr_t n; mpfr_init2 (n, 2); if (mpfr_signbit (mpc_realref (op))) mpfr_set_ui (n, 0, GMP_RNDN); else mpfr_set_inf (n, +1); if (mpfr_inf_p (mpc_imagref (op))) { inex_re = mpfr_set (mpc_realref (rop), n, GMP_RNDN); if (mpfr_signbit (mpc_realref (op))) inex_im = mpfr_set (mpc_imagref (rop), n, GMP_RNDN); else { mpfr_set_nan (mpc_imagref (rop)); inex_im = 0; /* NaN is exact */ } } else { mpfr_t c, s; mpfr_init2 (c, 2); mpfr_init2 (s, 2); mpfr_sin_cos (s, c, mpc_imagref (op), GMP_RNDN); inex_re = mpfr_copysign (mpc_realref (rop), n, c, GMP_RNDN); inex_im = mpfr_copysign (mpc_imagref (rop), n, s, GMP_RNDN); mpfr_clear (s); mpfr_clear (c); } mpfr_clear (n); return MPC_INEX(inex_re, inex_im); } if (mpfr_inf_p (mpc_imagref (op))) /* real part is finite non-zero number, imaginary part is an infinity */ { mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); return MPC_INEX(0, 0); /* NaN is exact */ } /* from now on, both parts of op are regular numbers */ prec = MPC_MAX_PREC(rop) + MPC_MAX (MPC_MAX (-mpfr_get_exp (mpc_realref (op)), 0), -mpfr_get_exp (mpc_imagref (op))); /* When op is close to 0, then exp is close to 1+Re(op), while cos is close to 1-Im(op); to decide on the ternary value of exp*cos, we need a high enough precision so that none of exp or cos is computed as 1. */ mpfr_init2 (x, 2); mpfr_init2 (y, 2); mpfr_init2 (z, 2); /* save the underflow or overflow flags from MPFR */ saved_underflow = mpfr_underflow_p (); saved_overflow = mpfr_overflow_p (); do { prec += mpc_ceil_log2 (prec) + 5; mpfr_set_prec (x, prec); mpfr_set_prec (y, prec); mpfr_set_prec (z, prec); /* FIXME: x may overflow so x.y does overflow too, while Re(exp(op)) could be represented in the precision of rop. */ mpfr_clear_overflow (); mpfr_clear_underflow (); mpfr_exp (x, mpc_realref(op), GMP_RNDN); /* error <= 0.5ulp */ mpfr_sin_cos (z, y, mpc_imagref(op), GMP_RNDN); /* errors <= 0.5ulp */ mpfr_mul (y, y, x, GMP_RNDN); /* error <= 2ulp */ ok = mpfr_overflow_p () || mpfr_zero_p (x) || mpfr_can_round (y, prec - 2, GMP_RNDN, GMP_RNDZ, MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == GMP_RNDN)); if (ok) /* compute imaginary part */ { mpfr_mul (z, z, x, GMP_RNDN); ok = mpfr_overflow_p () || mpfr_zero_p (x) || mpfr_can_round (z, prec - 2, GMP_RNDN, GMP_RNDZ, MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == GMP_RNDN)); } } while (ok == 0); inex_re = mpfr_set (mpc_realref(rop), y, MPC_RND_RE(rnd)); inex_im = mpfr_set (mpc_imagref(rop), z, MPC_RND_IM(rnd)); if (mpfr_overflow_p ()) { /* overflow in real exponential, inex is sign of infinite result */ inex_re = mpfr_sgn (y); inex_im = mpfr_sgn (z); } else if (mpfr_underflow_p ()) { /* underflow in real exponential, inex is opposite of sign of 0 result */ inex_re = (mpfr_signbit (y) ? +1 : -1); inex_im = (mpfr_signbit (z) ? +1 : -1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); /* restore underflow and overflow flags from MPFR */ if (saved_underflow) mpfr_set_underflow (); if (saved_overflow) mpfr_set_overflow (); return MPC_INEX(inex_re, inex_im); }