X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fmath%2Fgen%2Fmp.c;h=172b454e5e0fcf738cadf1ca27044605a0550f78;hb=db87a4c3abf99af95d5dfe27f77b6815ec27a4f4;hp=23a0fd3b7e3fc182e4987db56205434e0bdc0382;hpb=cb9f87af9a1f917facd1140603b24f1087729751;p=libc-test diff --git a/src/math/gen/mp.c b/src/math/gen/mp.c index 23a0fd3..172b454 100644 --- a/src/math/gen/mp.c +++ b/src/math/gen/mp.c @@ -123,7 +123,7 @@ static void genf(struct t *p, mpfr_t my, int t, int r) t = adjust(mr, my, t, r); 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; @@ -193,7 +193,7 @@ static void gend(struct t *p, mpfr_t my, int t, int r) t = adjust(mr, my, t, r); 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; @@ -268,7 +268,7 @@ static void genl(struct t *p, mpfr_t my, int t, int r) t = adjust(mr, my, t, r); 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; @@ -350,6 +350,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); @@ -468,30 +482,69 @@ 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); } @@ -566,6 +619,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); } @@ -734,6 +788,8 @@ int mpilogb(struct t *t) 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) @@ -743,6 +799,8 @@ int mpilogbf(struct t *t) 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) @@ -752,6 +810,8 @@ int mpilogbl(struct t *t) 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; } @@ -787,7 +847,7 @@ int mpmodf(struct t *t) return r; t->y2 = t->y; t->dy2 = t->dy; - e = t->e; + e = t->e & ~INEXACT; r = mpd1(t, mpfr_frac); t->e |= e; return r; @@ -802,7 +862,7 @@ int mpmodff(struct t *t) return r; t->y2 = t->y; t->dy2 = t->dy; - e = t->e; + e = t->e & ~INEXACT; r = mpf1(t, mpfr_frac); t->e |= e; return r; @@ -817,7 +877,7 @@ int mpmodfl(struct t *t) return r; t->y2 = t->y; t->dy2 = t->dy; - e = t->e; + e = t->e & ~INEXACT; r = mpl1(t, mpfr_frac); t->e |= e; return r; @@ -868,3 +928,98 @@ int mpsincosl(struct t *t) 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); + + mpsetup(); + 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); + if ((t->e & INEXACT) && nextafter(t->y, 0) == 0) { + mpfr_set_emin(-(1<<20)); + tn = mpfr_fma(my, mx, mx2, mx3, r); + mpfr_mul_2si(my, my, 1074, MPFR_RNDN); + t->dy = scalbnl(t->y, 1074) - mpfr_get_ld(my, r); + mpfr_set_emin(-1073); + } + 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); + + mpsetupf(); + 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); + if ((t->e & INEXACT) && nextafterf(t->y, 0) == 0) { + mpfr_set_emin(-(1<<20)); + tn = mpfr_fma(my, mx, mx2, mx3, r); + mpfr_mul_2si(my, my, 149, MPFR_RNDN); + t->dy = scalbnl(t->y, 149) - mpfr_get_ld(my, r); + mpfr_set_emin(-148); + } + 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); + + mpsetupl(); + 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); + if ((t->e & INEXACT) && nextafterl(t->y, 0) == 0) { + mpfr_set_emin(-(1<<20)); + tn = mpfr_fma(my, mx, mx2, mx3, r); + mpfr_mul_2si(my, my, 16445, MPFR_RNDN); + t->dy = scalbnl(t->y, 16445) - mpfr_get_ld(my, r); + mpfr_set_emin(-16444); + } + 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); } +