| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <stdio.h> /* for MPC_ASSERT */ |
| #include "mpc-impl.h" |
| |
| |
| static int |
| mpfr_fsss (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr c, mpfr_rnd_t rnd) |
| { |
| |
| |
| |
| |
| |
| int inex; |
| mpfr_t u, v; |
| |
| |
| mpfr_init2 (u, 2*mpfr_get_prec (a)); |
| mpfr_init2 (v, 2*mpfr_get_prec (c)); |
| mpfr_sqr (u, a, GMP_RNDN); |
| mpfr_sqr (v, c, GMP_RNDN); |
| |
| |
| |
| inex = mpfr_sub (z, u, v, rnd); |
| |
| if (mpfr_inf_p (z)) { |
| |
| mpfr_set_si (z, (mpfr_signbit (z) ? -1 : 1), GMP_RNDN); |
| inex = mpfr_mul_2ui (z, z, mpfr_get_emax (), rnd); |
| } |
| else if (mpfr_zero_p (u) && !mpfr_zero_p (v)) { |
| |
| inex = (mpfr_signbit (u) ? 1 : -1); |
| } |
| else if (mpfr_zero_p (v) && !mpfr_zero_p (u)) { |
| |
| inex = (mpfr_signbit (v) ? -1 : 1); |
| } |
| else if (mpfr_nan_p (z) || (mpfr_zero_p (u) && mpfr_zero_p (v))) { |
| |
| |
| |
| |
| mpfr_exp_t ea, ec; |
| mpz_t eu, ev; |
| |
| |
| |
| |
| ea = mpfr_get_exp (a); |
| ec = mpfr_get_exp (c); |
| |
| mpfr_set_exp ((mpfr_ptr) a, (mpfr_prec_t) 0); |
| mpfr_set_exp ((mpfr_ptr) c, (mpfr_prec_t) 0); |
| |
| mpz_init (eu); |
| mpz_init (ev); |
| mpz_set_si (eu, (long int) ea); |
| mpz_mul_2exp (eu, eu, 1); |
| mpz_set_si (ev, (long int) ec); |
| mpz_mul_2exp (ev, ev, 1); |
| |
| |
| mpfr_sqr (u, a, GMP_RNDN); |
| |
| mpz_sub_ui (eu, eu, (unsigned long int) (-mpfr_get_exp (u))); |
| mpfr_set_exp (u, (mpfr_prec_t) 0); |
| mpfr_sqr (v, c, GMP_RNDN); |
| mpz_sub_ui (ev, ev, (unsigned long int) (-mpfr_get_exp (v))); |
| mpfr_set_exp (v, (mpfr_prec_t) 0); |
| if (mpfr_nan_p (z)) { |
| mpfr_exp_t emax = mpfr_get_emax (); |
| int overflow; |
| |
| |
| |
| |
| |
| |
| if (mpz_cmp (eu, ev) >= 0) { |
| mpfr_set_exp (u, emax); |
| mpz_sub_ui (eu, eu, (long int) emax); |
| mpz_sub (ev, ev, eu); |
| mpfr_set_exp (v, (mpfr_exp_t) mpz_get_ui (ev)); |
| |
| } |
| else { |
| mpfr_set_exp (v, emax); |
| mpz_sub_ui (ev, ev, (long int) emax); |
| mpz_sub (eu, eu, ev); |
| mpfr_set_exp (u, (mpfr_exp_t) mpz_get_ui (eu)); |
| mpz_set (eu, ev); |
| |
| } |
| inex = mpfr_sub (z, u, v, rnd); |
| |
| overflow = mpfr_mul_2ui (z, z, mpz_get_ui (eu), rnd); |
| if (overflow) |
| inex = overflow; |
| } |
| else { |
| int underflow; |
| |
| |
| |
| mpfr_exp_t emin = mpfr_get_emin (); |
| if (mpz_cmp (eu, ev) <= 0) { |
| mpfr_set_exp (u, emin); |
| mpz_add_ui (eu, eu, (unsigned long int) (-emin)); |
| mpz_sub (ev, ev, eu); |
| mpfr_set_exp (v, (mpfr_exp_t) mpz_get_si (ev)); |
| } |
| else { |
| mpfr_set_exp (v, emin); |
| mpz_add_ui (ev, ev, (unsigned long int) (-emin)); |
| mpz_sub (eu, eu, ev); |
| mpfr_set_exp (u, (mpfr_exp_t) mpz_get_si (eu)); |
| mpz_set (eu, ev); |
| } |
| inex = mpfr_sub (z, u, v, rnd); |
| mpz_neg (eu, eu); |
| underflow = mpfr_div_2ui (z, z, mpz_get_ui (eu), rnd); |
| if (underflow) |
| inex = underflow; |
| } |
| |
| mpz_clear (eu); |
| mpz_clear (ev); |
| |
| mpfr_set_exp ((mpfr_ptr) a, ea); |
| mpfr_set_exp ((mpfr_ptr) c, ec); |
| |
| } |
| |
| mpfr_clear (u); |
| mpfr_clear (v); |
| |
| return inex; |
| } |
| |
| |
| int |
| mpc_sqr (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) |
| { |
| int ok; |
| mpfr_t u, v; |
| mpfr_t x; |
| |
| |
| mpfr_prec_t prec; |
| int inex_re, inex_im, inexact; |
| mpfr_exp_t emin; |
| int saved_underflow; |
| |
| |
| if (!mpc_fin_p (op)) { |
| if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op))) { |
| mpfr_set_nan (mpc_realref (rop)); |
| mpfr_set_nan (mpc_imagref (rop)); |
| } |
| else if (mpfr_inf_p (mpc_realref (op))) { |
| if (mpfr_inf_p (mpc_imagref (op))) { |
| mpfr_set_inf (mpc_imagref (rop), |
| MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op))); |
| mpfr_set_nan (mpc_realref (rop)); |
| } |
| else { |
| if (mpfr_zero_p (mpc_imagref (op))) |
| mpfr_set_nan (mpc_imagref (rop)); |
| else |
| mpfr_set_inf (mpc_imagref (rop), |
| MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op))); |
| mpfr_set_inf (mpc_realref (rop), +1); |
| } |
| } |
| else { |
| if (mpfr_zero_p (mpc_realref (op))) |
| mpfr_set_nan (mpc_imagref (rop)); |
| else |
| mpfr_set_inf (mpc_imagref (rop), |
| MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op))); |
| mpfr_set_inf (mpc_realref (rop), -1); |
| } |
| return MPC_INEX (0, 0); |
| } |
| |
| prec = MPC_MAX_PREC(rop); |
| |
| |
| if (mpfr_zero_p (mpc_imagref(op))) { |
| int same_sign = mpfr_signbit (mpc_realref (op)) == mpfr_signbit (mpc_imagref (op)); |
| inex_re = mpfr_sqr (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd)); |
| inex_im = mpfr_set_ui (mpc_imagref(rop), 0ul, GMP_RNDN); |
| if (!same_sign) |
| mpc_conj (rop, rop, MPC_RNDNN); |
| return MPC_INEX(inex_re, inex_im); |
| } |
| if (mpfr_zero_p (mpc_realref(op))) { |
| int same_sign = mpfr_signbit (mpc_realref (op)) == mpfr_signbit (mpc_imagref (op)); |
| inex_re = -mpfr_sqr (mpc_realref(rop), mpc_imagref(op), INV_RND (MPC_RND_RE(rnd))); |
| mpfr_neg (mpc_realref(rop), mpc_realref(rop), GMP_RNDN); |
| inex_im = mpfr_set_ui (mpc_imagref(rop), 0ul, GMP_RNDN); |
| if (!same_sign) |
| mpc_conj (rop, rop, MPC_RNDNN); |
| return MPC_INEX(inex_re, inex_im); |
| } |
| |
| if (rop == op) |
| { |
| mpfr_init2 (x, MPC_PREC_RE (op)); |
| mpfr_set (x, op->re, GMP_RNDN); |
| } |
| else |
| x [0] = op->re [0]; |
| |
| |
| |
| if (SAFE_ABS (mpfr_exp_t, |
| mpfr_get_exp (mpc_realref (op)) - mpfr_get_exp (mpc_imagref (op))) |
| > (mpfr_exp_t) MPC_MAX_PREC (op) / 2) { |
| |
| |
| |
| |
| |
| |
| inex_re = mpfr_fsss (rop->re, x, op->im, MPC_RND_RE (rnd)); |
| } |
| else { |
| |
| |
| |
| mpfr_init (u); |
| mpfr_init (v); |
| |
| emin = mpfr_get_emin (); |
| |
| do |
| { |
| prec += mpc_ceil_log2 (prec) + 5; |
| |
| mpfr_set_prec (u, prec); |
| mpfr_set_prec (v, prec); |
| |
| |
| |
| |
| |
| inexact = ROUND_AWAY (mpfr_add (u, x, mpc_imagref (op), MPFR_RNDA), u) |
| | ROUND_AWAY (mpfr_sub (v, x, mpc_imagref (op), MPFR_RNDA), v); |
| |
| |
| |
| |
| if (mpfr_sgn (u) == 0 || mpfr_sgn (v) == 0) { |
| |
| mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN); |
| inex_re = 0; |
| ok = 1; |
| } |
| else { |
| mpfr_rnd_t rnd_away; |
| |
| rnd_away = (mpfr_sgn (u) * mpfr_sgn (v) > 0 ? GMP_RNDU : GMP_RNDD); |
| inexact |= ROUND_AWAY (mpfr_mul (u, u, v, MPFR_RNDA), u); |
| if (mpfr_get_exp (u) == emin || mpfr_inf_p (u)) { |
| |
| inex_re = mpfr_fsss (rop->re, x, op->im, MPC_RND_RE (rnd)); |
| ok = 1; |
| } |
| else { |
| ok = (!inexact) | mpfr_can_round (u, prec - 3, |
| rnd_away, GMP_RNDZ, |
| MPC_PREC_RE (rop) + (MPC_RND_RE (rnd) == GMP_RNDN)); |
| if (ok) { |
| inex_re = mpfr_set (mpc_realref (rop), u, MPC_RND_RE (rnd)); |
| if (inex_re == 0) |
| |
| inex_re = inexact; |
| } |
| } |
| } |
| } |
| while (!ok); |
| |
| mpfr_clear (u); |
| mpfr_clear (v); |
| } |
| |
| saved_underflow = mpfr_underflow_p (); |
| mpfr_clear_underflow (); |
| inex_im = mpfr_mul (rop->im, x, op->im, MPC_RND_IM (rnd)); |
| if (!mpfr_underflow_p ()) |
| inex_im |= mpfr_mul_2ui (rop->im, rop->im, 1, MPC_RND_IM (rnd)); |
| |
| |
| if (saved_underflow) |
| mpfr_set_underflow (); |
| |
| if (rop == op) |
| mpfr_clear (x); |
| |
| return MPC_INEX (inex_re, inex_im); |
| } |