X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fmath%2Fgen%2Fmp.c;h=eca0b693c6d9c9842ad4ffbe3e878d675e87f5b5;hb=b35e816189efde540e299412172acf6cd987dfdd;hp=56badb53c57bac89de98ee87185d55e09bc77d44;hpb=457b0dbfc1d72080f6ba9fe47cd712e0f090732a;p=libc-test diff --git a/src/math/gen/mp.c b/src/math/gen/mp.c index 56badb5..eca0b69 100644 --- a/src/math/gen/mp.c +++ b/src/math/gen/mp.c @@ -1,5 +1,4 @@ #include - #include #include #include "gen.h" @@ -15,30 +14,24 @@ static int rmap(int r) return -1; } +enum {FLT, DBL, LDBL}; +static const int emin[] = { +[FLT] = -148, +[DBL] = -1073, +[LDBL] = -16444 +}; +static const int emax[] = { +[FLT] = 128, +[DBL] = 1024, +[LDBL] = 16384 +}; + void debug(mpfr_t x) { mpfr_out_str(stdout, 10, 0, x, MPFR_RNDN); printf("\n"); } -void mpsetup() -{ - mpfr_set_emin(-1073); - mpfr_set_emax(1024); -} -void mpsetupf() -{ - mpfr_set_emin(-148); - mpfr_set_emax(128); -} -#if LDBL_MANT_DIG == 64 -void mpsetupl() -{ - mpfr_set_emin(-16444); - mpfr_set_emax(16384); -} -#endif - /* round x into y considering x is already rounded (t = up or down) @@ -75,7 +68,7 @@ static int adjust_round(mpfr_t y, mpfr_t x, int t, int r) return mpfr_set(y, x, r); } -static int adjust(mpfr_t mr, mpfr_t my, int t, int r) +static int adjust(mpfr_t mr, mpfr_t my, int t, int r, int type) { // double d, dn, dp; //printf("adj %d\n", t); @@ -83,7 +76,13 @@ static int adjust(mpfr_t mr, mpfr_t my, int t, int r) t = adjust_round(mr, my, t, r); //printf("rnd %d\n", t); //debug(mr); + mpfr_set_emin(emin[type]); + mpfr_set_emax(emax[type]); + // mpfr could handle this in subnormlize easily but no it doesnt... + t = mpfr_check_range(mr, t, r); t = mpfr_subnormalize(mr, t, r); + mpfr_set_emax(MPFR_EMAX_DEFAULT); + mpfr_set_emin(MPFR_EMIN_DEFAULT); //printf("sub %d\n", t); //debug(mr); // d = mpfr_get_d(mr, r); @@ -121,21 +120,21 @@ static void genf(struct t *p, mpfr_t my, int t, int r) MPFR_DECL_INIT(mr, 24); int i; - t = adjust(mr, my, t, r); + t = adjust(mr, my, t, r, FLT); p->y = mpfr_get_flt(mr, r); - p->e = eflags(isnan(p->x) || isnan(p->x2)); + p->e = eflags(isnan(p->x) || isnan(p->x2) || isnan(p->x3)); i = eulpf(p->y); if (!isfinite(p->y)) { p->dy = 0; - } else if (i < 0) { - mpfr_div_2si(mr, mr, i, MPFR_RNDN); - mpfr_div_2si(my, my, i, MPFR_RNDN); - mpfr_sub(my, mr, my, MPFR_RNDN); - p->dy = mpfr_get_flt(my, r); } else { mpfr_sub(my, mr, my, MPFR_RNDN); mpfr_div_2si(my, my, i, MPFR_RNDN); - p->dy = mpfr_get_flt(my, r); + p->dy = mpfr_get_flt(my, MPFR_RNDN); + // happens in RU,RD,RZ modes when y is finite but outside the domain + if (p->dy > 1) + p->dy = 1; + if (p->dy < -1) + p->dy = -1; } } @@ -146,19 +145,11 @@ static int mpf1(struct t *p, int (*fmp)(mpfr_t, const mpfr_t, mpfr_rnd_t)) MPFR_DECL_INIT(mx, 24); MPFR_DECL_INIT(my, 128); - mpsetupf(); mpfr_clear_flags(); mpfr_set_flt(mx, p->x, MPFR_RNDN); tn = fmp(my, mx, r); p->x2 = 0; genf(p, my, tn, r); - if ((p->e & INEXACT) && nextafterf(p->y, 0) == 0) { - mpfr_set_emin(-(1<<20)); - tn = fmp(my, mx, r); - mpfr_mul_2si(my, my, 149, MPFR_RNDN); - p->dy = scalbnl(p->y, 149) - mpfr_get_ld(my, r); - mpfr_set_emin(-148); - } return 0; } @@ -170,19 +161,11 @@ static int mpf2(struct t *p, int (*fmp)(mpfr_t, const mpfr_t, const mpfr_t, mpfr MPFR_DECL_INIT(mx2, 24); MPFR_DECL_INIT(my, 128); - mpsetupf(); mpfr_clear_flags(); mpfr_set_flt(mx, p->x, MPFR_RNDN); mpfr_set_flt(mx2, p->x2, MPFR_RNDN); tn = fmp(my, mx, mx2, r); genf(p, my, tn, r); - if ((p->e & INEXACT) && nextafterf(p->y, 0) == 0) { - mpfr_set_emin(-(1<<20)); - tn = fmp(my, mx, mx2, r); - mpfr_mul_2si(my, my, 149, MPFR_RNDN); - p->dy = scalbnl(p->y, 149) - mpfr_get_ld(my, r); - mpfr_set_emin(-148); - } return 0; } @@ -191,21 +174,21 @@ static void gend(struct t *p, mpfr_t my, int t, int r) MPFR_DECL_INIT(mr, 53); int i; - t = adjust(mr, my, t, r); + t = adjust(mr, my, t, r, DBL); p->y = mpfr_get_d(mr, r); - p->e = eflags(isnan(p->x) || isnan(p->x2)); + p->e = eflags(isnan(p->x) || isnan(p->x2) || isnan(p->x3)); i = eulp(p->y); if (!isfinite(p->y)) { p->dy = 0; - } else if (i < 0) { - mpfr_div_2si(mr, mr, i, MPFR_RNDN); - mpfr_div_2si(my, my, i, MPFR_RNDN); - mpfr_sub(my, mr, my, MPFR_RNDN); - p->dy = mpfr_get_flt(my, r); } else { mpfr_sub(my, mr, my, MPFR_RNDN); mpfr_div_2si(my, my, i, MPFR_RNDN); - p->dy = mpfr_get_flt(my, r); + p->dy = mpfr_get_flt(my, MPFR_RNDN); + // happens in RU,RD,RZ modes when y is finite but outside the domain + if (p->dy > 1) + p->dy = 1; + if (p->dy < -1) + p->dy = -1; } } @@ -216,23 +199,11 @@ static int mpd1(struct t *p, int (*fmp)(mpfr_t, const mpfr_t, mpfr_rnd_t)) MPFR_DECL_INIT(mx, 53); MPFR_DECL_INIT(my, 128); - mpsetup(); mpfr_clear_flags(); mpfr_set_d(mx, p->x, MPFR_RNDN); tn = fmp(my, mx, r); -//printf("underflow: %d\n", mpfr_underflow_p()); p->x2 = 0; gend(p, my, tn, r); -//printf("dy: %a %.3f\n", p->dy, p->dy); - if ((p->e & INEXACT) && nextafter(p->y, 0) == 0) { - mpfr_set_emin(-(1<<20)); - tn = fmp(my, mx, r); - mpfr_mul_2si(my, my, 1074, MPFR_RNDN); -//debug(my); - p->dy = scalbnl(p->y, 1074) - mpfr_get_ld(my, r); -//printf("dy: %a %.3f\n", p->dy, p->dy); - mpfr_set_emin(-1073); - } return 0; } @@ -244,19 +215,11 @@ static int mpd2(struct t *p, int (*fmp)(mpfr_t, const mpfr_t, const mpfr_t, mpfr MPFR_DECL_INIT(mx2, 53); MPFR_DECL_INIT(my, 128); - mpsetup(); mpfr_clear_flags(); mpfr_set_d(mx, p->x, MPFR_RNDN); mpfr_set_d(mx2, p->x2, MPFR_RNDN); tn = fmp(my, mx, mx2, r); gend(p, my, tn, r); - if ((p->e & INEXACT) && nextafter(p->y, 0) == 0) { - mpfr_set_emin(-(1<<20)); - tn = fmp(my, mx, mx2, r); - mpfr_mul_2si(my, my, 1074, MPFR_RNDN); - p->dy = scalbnl(p->y, 1074) - mpfr_get_ld(my, r); - mpfr_set_emin(-1073); - } return 0; } @@ -266,21 +229,21 @@ static void genl(struct t *p, mpfr_t my, int t, int r) MPFR_DECL_INIT(mr, 64); int i; - t = adjust(mr, my, t, r); + t = adjust(mr, my, t, r, LDBL); p->y = mpfr_get_ld(mr, r); - p->e = eflags(isnan(p->x) || isnan(p->x2)); + p->e = eflags(isnan(p->x) || isnan(p->x2) || isnan(p->x3)); i = eulpl(p->y); if (!isfinite(p->y)) { p->dy = 0; - } else if (i < 0) { - mpfr_div_2si(mr, mr, i, MPFR_RNDN); - mpfr_div_2si(my, my, i, MPFR_RNDN); - mpfr_sub(my, mr, my, MPFR_RNDN); - p->dy = mpfr_get_flt(my, r); } else { mpfr_sub(my, mr, my, MPFR_RNDN); mpfr_div_2si(my, my, i, MPFR_RNDN); - p->dy = mpfr_get_flt(my, r); + p->dy = mpfr_get_flt(my, MPFR_RNDN); + // happens in RU,RD,RZ modes when y is finite but outside the domain + if (p->dy > 1) + p->dy = 1; + if (p->dy < -1) + p->dy = -1; } } #endif @@ -295,19 +258,11 @@ static int mpl1(struct t *p, int (*fmp)(mpfr_t, const mpfr_t, mpfr_rnd_t)) MPFR_DECL_INIT(mx, 64); MPFR_DECL_INIT(my, 128); - mpsetupl(); mpfr_clear_flags(); mpfr_set_ld(mx, p->x, MPFR_RNDN); tn = fmp(my, mx, r); p->x2 = 0; genl(p, my, tn, r); - if ((p->e & INEXACT) && nextafterl(p->y, 0) == 0) { - mpfr_set_emin(-(1<<20)); - tn = fmp(my, mx, r); - mpfr_mul_2si(my, my, 16445, MPFR_RNDN); - p->dy = scalbnl(p->y, 16445) - mpfr_get_ld(my, r); - mpfr_set_emin(-16444); - } return 0; #else return -1; @@ -325,19 +280,11 @@ static int mpl2(struct t *p, int (*fmp)(mpfr_t, const mpfr_t, const mpfr_t, mpfr MPFR_DECL_INIT(mx2, 64); MPFR_DECL_INIT(my, 128); - mpsetupl(); mpfr_clear_flags(); mpfr_set_ld(mx, p->x, MPFR_RNDN); mpfr_set_ld(mx2, p->x2, MPFR_RNDN); tn = fmp(my, mx, mx2, r); genl(p, my, tn, r); - if ((p->e & INEXACT) && nextafterl(p->y, 0) == 0) { - mpfr_set_emin(-(1<<20)); - tn = fmp(my, mx, mx2, r); - mpfr_mul_2si(my, my, 16445, MPFR_RNDN); - p->dy = scalbnl(p->y, 16445) - mpfr_get_ld(my, r); - mpfr_set_emin(-16444); - } return 0; #else return -1; @@ -350,6 +297,20 @@ static int wrap_lgamma(mpfr_t my, const mpfr_t mx, mpfr_rnd_t r) { return mpfr_lgamma(my, &mplgamma_sign, mx, r); } +static long mpremquo_q; +static int wrap_remquo(mpfr_t my, const mpfr_t mx, const mpfr_t mx2, mpfr_rnd_t r) +{ + return mpfr_remquo(my, &mpremquo_q, mx, mx2, r); +} +static int mpbessel_n; +static int wrap_jn(mpfr_t my, const mpfr_t mx, mpfr_rnd_t r) +{ + return mpfr_jn(my, mpbessel_n, mx, r); +} +static int wrap_yn(mpfr_t my, const mpfr_t mx, mpfr_rnd_t r) +{ + return mpfr_yn(my, mpbessel_n, mx, r); +} static int wrap_ceil(mpfr_t my, const mpfr_t mx, mpfr_rnd_t r) { return mpfr_ceil(my, mx); @@ -377,6 +338,27 @@ static int wrap_pow10(mpfr_t my, const mpfr_t mx, mpfr_rnd_t r) return mpfr_ui_pow(my, 10, mx, r); } + +static int wrap_sinpi(mpfr_t my, const mpfr_t mx, mpfr_rnd_t r) +{ + // hack because mpfr has no sinpi + MPFR_DECL_INIT(mz, 4096); + mpfr_const_pi(mz, r); + mpfr_mul(mz,mz,mx,r); + return mpfr_sin(my, mz, r); +} +int mpsinpi(struct t *t) { return mpd1(t, wrap_sinpi); } + +int mpadd(struct t *t) { return mpd2(t, mpfr_add); } +int mpaddf(struct t *t) { return mpf2(t, mpfr_add); } +int mpaddl(struct t *t) { return mpl2(t, mpfr_add); } +int mpmul(struct t *t) { return mpd2(t, mpfr_mul); } +int mpmulf(struct t *t) { return mpf2(t, mpfr_mul); } +int mpmull(struct t *t) { return mpl2(t, mpfr_mul); } +int mpdiv(struct t *t) { return mpd2(t, mpfr_div); } +int mpdivf(struct t *t) { return mpf2(t, mpfr_div); } +int mpdivl(struct t *t) { return mpl2(t, mpfr_div); } + int mpacos(struct t *t) { return mpd1(t, mpfr_acos); } int mpacosf(struct t *t) { return mpf1(t, mpfr_acos); } int mpacosl(struct t *t) { return mpl1(t, mpfr_acos); } @@ -468,39 +450,116 @@ int mplogb(struct t *t) { MPFR_DECL_INIT(mx, 53); - mpfr_set_d(mx, t->x, MPFR_RNDN); - t->y = mpfr_get_exp(mx) - 1; t->dy = 0; t->e = 0; + if (t->x == 0) { + t->y = -INFINITY; + t->e |= DIVBYZERO; + return 0; + } + if (isinf(t->x)) { + t->y = INFINITY; + return 0; + } + if (isnan(t->x)) { + t->y = t->x; + return 0; + } + mpfr_set_d(mx, t->x, MPFR_RNDN); + t->y = mpfr_get_exp(mx) - 1; return 0; } int mplogbf(struct t *t) { MPFR_DECL_INIT(mx, 24); - mpfr_set_flt(mx, t->x, MPFR_RNDN); - t->y = mpfr_get_exp(mx) - 1; t->dy = 0; t->e = 0; + if (t->x == 0) { + t->y = -INFINITY; + t->e |= DIVBYZERO; + return 0; + } + if (isinf(t->x)) { + t->y = INFINITY; + return 0; + } + if (isnan(t->x)) { + t->y = t->x; + return 0; + } + mpfr_set_flt(mx, t->x, MPFR_RNDN); + t->y = mpfr_get_exp(mx) - 1; return 0; } int mplogbl(struct t *t) { MPFR_DECL_INIT(mx, 64); - mpfr_set_ld(mx, t->x, MPFR_RNDN); - t->y = mpfr_get_exp(mx) - 1; t->dy = 0; t->e = 0; + if (t->x == 0) { + t->y = -INFINITY; + t->e |= DIVBYZERO; + return 0; + } + if (isinf(t->x)) { + t->y = INFINITY; + return 0; + } + if (isnan(t->x)) { + t->y = t->x; + return 0; + } + mpfr_set_ld(mx, t->x, MPFR_RNDN); + t->y = mpfr_get_exp(mx) - 1; return 0; } int mpnearbyint(struct t *t) { return mpd1(t, wrap_nearbyint) || (t->e&=~INEXACT, 0); } int mpnearbyintf(struct t *t) { return mpf1(t, wrap_nearbyint) || (t->e&=~INEXACT, 0); } int mpnearbyintl(struct t *t) { return mpl1(t, wrap_nearbyint) || (t->e&=~INEXACT, 0); } -int mpnextafter(struct t *t) { return -1; } -int mpnextafterf(struct t *t) { return -1; } -int mpnextafterl(struct t *t) { return -1; } -int mpnexttowardl(struct t *t) { return -1; } +// TODO: hard to implement with mpfr +int mpnextafter(struct t *t) +{ + feclearexcept(FE_ALL_EXCEPT); + t->y = nextafter(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; + return 0; +} +int mpnextafterf(struct t *t) +{ + feclearexcept(FE_ALL_EXCEPT); + t->y = nextafterf(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; + return 0; +} +int mpnextafterl(struct t *t) +{ + feclearexcept(FE_ALL_EXCEPT); + t->y = nextafterl(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; + return 0; +} +int mpnexttoward(struct t *t) +{ + feclearexcept(FE_ALL_EXCEPT); + t->y = nexttoward(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; + return 0; +} +int mpnexttowardf(struct t *t) +{ + feclearexcept(FE_ALL_EXCEPT); + t->y = nexttowardf(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; + return 0; +} +int mpnexttowardl(struct t *t) { return mpnextafterl(t); } int mppow(struct t *t) { return mpd2(t, mpfr_pow); } int mppowf(struct t *t) { return mpf2(t, mpfr_pow); } int mppowl(struct t *t) { return mpl2(t, mpfr_pow); } @@ -528,6 +587,7 @@ int mptanl(struct t *t) { return mpl1(t, mpfr_tan); } int mptanh(struct t *t) { return mpd1(t, mpfr_tanh); } int mptanhf(struct t *t) { return mpf1(t, mpfr_tanh); } int mptanhl(struct t *t) { return mpl1(t, mpfr_tanh); } +// TODO: tgamma(2) raises wrong flags int mptgamma(struct t *t) { return mpd1(t, mpfr_gamma); } int mptgammaf(struct t *t) { return mpf1(t, mpfr_gamma); } int mptgammal(struct t *t) { return mpl1(t, mpfr_gamma); } @@ -538,8 +598,23 @@ int mpj0(struct t *t) { return mpd1(t, mpfr_j0); } int mpj1(struct t *t) { return mpd1(t, mpfr_j1); } int mpy0(struct t *t) { return mpd1(t, mpfr_y0); } int mpy1(struct t *t) { return mpd1(t, mpfr_y1); } -int mpscalb(struct t *t) { return -1; } -int mpscalbf(struct t *t) { return -1; } +// TODO: non standard functions +int mpscalb(struct t *t) +{ + setupfenv(t->r); + t->y = scalb(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; // wrong + return 0; +} +int mpscalbf(struct t *t) +{ + setupfenv(t->r); + t->y = scalbf(t->x, t->x2); + t->e = getexcept(); + t->dy = 0; // wrong + return 0; +} int mpj0f(struct t *t) { return mpf1(t, mpfr_j0); } int mpj0l(struct t *t) { return mpl1(t, mpfr_j0); } int mpj1f(struct t *t) { return mpf1(t, mpfr_j1); } @@ -563,11 +638,9 @@ int mpfrexp(struct t *t) t->dy = 0; t->y = 0; - mpsetup(); mpfr_clear_flags(); mpfr_set_d(mx, t->x, MPFR_RNDN); k = mpfr_frexp(&e, mx, mx, t->r); - mpfr_subnormalize(mx, k, t->r); t->y = mpfr_get_d(mx, MPFR_RNDN); t->i = e; t->e = eflags(isnan(t->x)); @@ -582,11 +655,9 @@ int mpfrexpf(struct t *t) t->dy = 0; t->y = 0; - mpsetup(); mpfr_clear_flags(); mpfr_set_flt(mx, t->x, MPFR_RNDN); k = mpfr_frexp(&e, mx, mx, t->r); - mpfr_subnormalize(mx, k, t->r); t->y = mpfr_get_flt(mx, MPFR_RNDN); t->i = e; t->e = eflags(isnan(t->x)); @@ -601,11 +672,9 @@ int mpfrexpl(struct t *t) t->dy = 0; t->y = 0; - mpsetup(); mpfr_clear_flags(); mpfr_set_ld(mx, t->x, MPFR_RNDN); k = mpfr_frexp(&e, mx, mx, t->r); - mpfr_subnormalize(mx, k, t->r); t->y = mpfr_get_ld(mx, MPFR_RNDN); t->i = e; t->e = eflags(isnan(t->x)); @@ -619,11 +688,10 @@ int mpldexp(struct t *t) t->dy = 0; t->y = 0; - mpsetup(); mpfr_clear_flags(); mpfr_set_d(mx, t->x, MPFR_RNDN); k = mpfr_mul_2si(mx, mx, t->i, t->r); - mpfr_subnormalize(mx, k, t->r); + adjust(mx, mx, k, t->r, DBL); t->y = mpfr_get_d(mx, MPFR_RNDN); t->e = eflags(isnan(t->x)); return 0; @@ -636,11 +704,10 @@ int mpldexpf(struct t *t) t->dy = 0; t->y = 0; - mpsetup(); mpfr_clear_flags(); mpfr_set_flt(mx, t->x, MPFR_RNDN); k = mpfr_mul_2si(mx, mx, t->i, t->r); - mpfr_subnormalize(mx, k, t->r); + adjust(mx, mx, k, t->r, FLT); t->y = mpfr_get_flt(mx, MPFR_RNDN); t->e = eflags(isnan(t->x)); return 0; @@ -653,11 +720,10 @@ int mpldexpl(struct t *t) t->dy = 0; t->y = 0; - mpsetup(); mpfr_clear_flags(); mpfr_set_ld(mx, t->x, MPFR_RNDN); k = mpfr_mul_2si(mx, mx, t->i, t->r); - mpfr_subnormalize(mx, k, t->r); + adjust(mx, mx, k, t->r, LDBL); t->y = mpfr_get_ld(mx, MPFR_RNDN); t->e = eflags(isnan(t->x)); return 0; @@ -673,3 +739,224 @@ int mpscalblnl(struct t *t) { return mpldexpl(t); } int mplgamma_r(struct t *t) { return mplgamma(t); } int mplgammaf_r(struct t *t) { return mplgammaf(t); } int mplgammal_r(struct t *t) { return mplgammal(t); } + +int mpilogb(struct t *t) +{ + MPFR_DECL_INIT(mx, 53); + + mpfr_set_d(mx, t->x, MPFR_RNDN); + t->i = mpfr_get_exp(mx) - 1; + t->e = 0; + if (isinf(t->x) || isnan(t->x) || t->x == 0) + t->e = INVALID; + return 0; +} +int mpilogbf(struct t *t) +{ + MPFR_DECL_INIT(mx, 24); + + mpfr_set_flt(mx, t->x, MPFR_RNDN); + t->i = mpfr_get_exp(mx) - 1; + t->e = 0; + if (isinf(t->x) || isnan(t->x) || t->x == 0) + t->e = INVALID; + return 0; +} +int mpilogbl(struct t *t) +{ + MPFR_DECL_INIT(mx, 64); + + mpfr_set_ld(mx, t->x, MPFR_RNDN); + t->i = mpfr_get_exp(mx) - 1; + t->e = 0; + if (isinf(t->x) || isnan(t->x) || t->x == 0) + t->e = INVALID; + return 0; +} + +// TODO: ll* is hard to do with mpfr +#define mp_f_i(n) \ +int mp##n(struct t *t) \ +{ \ + setupfenv(t->r); \ + t->i = n(t->x); \ + t->e = getexcept(); \ + if (t->e & INVALID) \ + t->i = 0; \ + return 0; \ +} + +mp_f_i(llrint) +mp_f_i(llrintf) +mp_f_i(llrintl) +mp_f_i(lrint) +mp_f_i(lrintf) +mp_f_i(lrintl) +mp_f_i(llround) +mp_f_i(llroundf) +mp_f_i(llroundl) +mp_f_i(lround) +mp_f_i(lroundf) +mp_f_i(lroundl) + +int mpmodf(struct t *t) +{ + int e, r; + + r = mpd1(t, wrap_trunc); + if (r) + return r; + t->y2 = t->y; + t->dy2 = t->dy; + e = t->e & ~INEXACT; + r = mpd1(t, mpfr_frac); + t->e |= e; + return r; +} + +int mpmodff(struct t *t) +{ + int e, r; + + r = mpf1(t, wrap_trunc); + if (r) + return r; + t->y2 = t->y; + t->dy2 = t->dy; + e = t->e & ~INEXACT; + r = mpf1(t, mpfr_frac); + t->e |= e; + return r; +} + +int mpmodfl(struct t *t) +{ + int e, r; + + r = mpl1(t, wrap_trunc); + if (r) + return r; + t->y2 = t->y; + t->dy2 = t->dy; + e = t->e & ~INEXACT; + r = mpl1(t, mpfr_frac); + t->e |= e; + return r; +} + +int mpsincos(struct t *t) +{ + int e, r; + + r = mpd1(t, mpfr_cos); + if (r) + return r; + t->y2 = t->y; + t->dy2 = t->dy; + e = t->e; + r = mpd1(t, mpfr_sin); + t->e |= e; + return r; +} + +int mpsincosf(struct t *t) +{ + int e, r; + + r = mpf1(t, mpfr_cos); + if (r) + return r; + t->y2 = t->y; + t->dy2 = t->dy; + e = t->e; + r = mpf1(t, mpfr_sin); + t->e |= e; + return r; +} + +int mpsincosl(struct t *t) +{ + int e, r; + + r = mpl1(t, mpfr_cos); + if (r) + return r; + t->y2 = t->y; + t->dy2 = t->dy; + e = t->e; + r = mpl1(t, mpfr_sin); + t->e |= e; + return r; +} + +int mpremquo(struct t *t) { return mpd2(t, wrap_remquo) || (t->i = mpremquo_q, 0); } +int mpremquof(struct t *t) { return mpf2(t, wrap_remquo) || (t->i = mpremquo_q, 0); } +int mpremquol(struct t *t) { return mpl2(t, wrap_remquo) || (t->i = mpremquo_q, 0); } + +int mpfma(struct t *t) +{ + int tn; + int r = rmap(t->r); + MPFR_DECL_INIT(mx, 53); + MPFR_DECL_INIT(mx2, 53); + MPFR_DECL_INIT(mx3, 53); + MPFR_DECL_INIT(my, 128); + + mpfr_clear_flags(); + mpfr_set_d(mx, t->x, MPFR_RNDN); + mpfr_set_d(mx2, t->x2, MPFR_RNDN); + mpfr_set_d(mx3, t->x3, MPFR_RNDN); + tn = mpfr_fma(my, mx, mx2, mx3, r); + gend(t, my, tn, r); + return 0; +} + +int mpfmaf(struct t *t) +{ + int tn; + int r = rmap(t->r); + MPFR_DECL_INIT(mx, 24); + MPFR_DECL_INIT(mx2, 24); + MPFR_DECL_INIT(mx3, 24); + MPFR_DECL_INIT(my, 128); + + mpfr_clear_flags(); + mpfr_set_flt(mx, t->x, MPFR_RNDN); + mpfr_set_flt(mx2, t->x2, MPFR_RNDN); + mpfr_set_flt(mx3, t->x3, MPFR_RNDN); + tn = mpfr_fma(my, mx, mx2, mx3, r); + genf(t, my, tn, r); + return 0; +} + +int mpfmal(struct t *t) +{ +#if LDBL_MANT_DIG == 53 + return mpfma(t); +#elif LDBL_MANT_DIG == 64 + int tn; + int r = rmap(t->r); + MPFR_DECL_INIT(mx, 64); + MPFR_DECL_INIT(mx2, 64); + MPFR_DECL_INIT(mx3, 64); + MPFR_DECL_INIT(my, 128); + + mpfr_clear_flags(); + mpfr_set_ld(mx, t->x, MPFR_RNDN); + mpfr_set_ld(mx2, t->x2, MPFR_RNDN); + mpfr_set_ld(mx3, t->x3, MPFR_RNDN); + tn = mpfr_fma(my, mx, mx2, mx3, r); + genl(t, my, tn, r); + return 0; +#else + return -1; +#endif +} + +int mpjn(struct t *t) { mpbessel_n = t->i; return mpd1(t, wrap_jn); } +int mpjnf(struct t *t) { mpbessel_n = t->i; return mpf1(t, wrap_jn); } +int mpjnl(struct t *t) { mpbessel_n = t->i; return mpl1(t, wrap_jn); } +int mpyn(struct t *t) { mpbessel_n = t->i; return mpd1(t, wrap_yn); } +int mpynf(struct t *t) { mpbessel_n = t->i; return mpf1(t, wrap_yn); } +int mpynl(struct t *t) { mpbessel_n = t->i; return mpl1(t, wrap_yn); } +