| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <limits.h> /* for CHAR_BIT */ |
| #include "mpc-impl.h" |
| |
| |
| |
| |
| |
| static int |
| mpc_log10_aux (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd, int flag, int nb) |
| { |
| mp_prec_t prec = (MPFR_PREC_MIN > 4) ? MPFR_PREC_MIN : 4; |
| mpc_t tmp; |
| mpfr_t log10; |
| int ok = 0, ret; |
| |
| prec = mpfr_get_prec ((flag == 0) ? mpc_realref (rop) : mpc_imagref (rop)); |
| prec += 10; |
| mpc_init2 (tmp, prec); |
| mpfr_init2 (log10, prec); |
| while (ok == 0) |
| { |
| mpfr_set_ui (log10, 10, GMP_RNDN); |
| mpfr_log (log10, log10, GMP_RNDN); |
| |
| |
| |
| switch (nb) |
| { |
| case 0: |
| mpfr_atan2 (mpc_imagref (tmp), mpc_imagref (op), mpc_realref (op), |
| MPC_RND_IM (rnd)); |
| mpfr_div (mpc_imagref (tmp), mpc_imagref (tmp), log10, GMP_RNDN); |
| ok = mpfr_can_round (mpc_imagref (tmp), prec - 2, GMP_RNDN, |
| GMP_RNDZ, MPC_PREC_IM(rop) + |
| (MPC_RND_IM (rnd) == GMP_RNDN)); |
| if (ok) |
| ret = mpfr_set (mpc_imagref (rop), mpc_imagref (tmp), |
| MPC_RND_IM (rnd)); |
| break; |
| case 1: |
| mpfr_log (mpc_realref (tmp), mpc_realref (op), MPC_RND_RE (rnd)); |
| mpfr_div (mpc_realref (tmp), mpc_realref (tmp), log10, GMP_RNDN); |
| ok = mpfr_can_round (mpc_realref (tmp), prec - 2, GMP_RNDN, |
| GMP_RNDZ, MPC_PREC_RE(rop) + |
| (MPC_RND_RE (rnd) == GMP_RNDN)); |
| if (ok) |
| ret = mpfr_set (mpc_realref (rop), mpc_realref (tmp), |
| MPC_RND_RE (rnd)); |
| break; |
| case 2: |
| mpfr_const_pi (mpc_imagref (tmp), MPC_RND_IM (rnd)); |
| mpfr_div (mpc_imagref (tmp), mpc_imagref (tmp), log10, GMP_RNDN); |
| ok = mpfr_can_round (mpc_imagref (tmp), prec - 2, GMP_RNDN, |
| GMP_RNDZ, MPC_PREC_IM(rop) + |
| (MPC_RND_IM (rnd) == GMP_RNDN)); |
| if (ok) |
| ret = mpfr_set (mpc_imagref (rop), mpc_imagref (tmp), |
| MPC_RND_IM (rnd)); |
| break; |
| } |
| prec += prec / 2; |
| mpc_set_prec (tmp, prec); |
| mpfr_set_prec (log10, prec); |
| } |
| mpc_clear (tmp); |
| mpfr_clear (log10); |
| return ret; |
| } |
| |
| int |
| mpc_log10 (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) |
| { |
| int ok = 0, loops = 0, re_cmp, im_cmp, inex_re, inex_im, negative_zero; |
| mpfr_t w; |
| mpfr_prec_t prec; |
| mpfr_rnd_t rnd_im; |
| mpc_t ww; |
| mpc_rnd_t invrnd; |
| |
| |
| if (!mpc_fin_p (op)) |
| { |
| if (mpfr_nan_p (mpc_realref (op))) |
| { |
| if (mpfr_inf_p (mpc_imagref (op))) |
| |
| mpfr_set_inf (mpc_realref (rop), +1); |
| else |
| |
| mpfr_set_nan (mpc_realref (rop)); |
| mpfr_set_nan (mpc_imagref (rop)); |
| inex_im = 0; |
| } |
| else if (mpfr_nan_p (mpc_imagref (op))) |
| { |
| if (mpfr_inf_p (mpc_realref (op))) |
| |
| mpfr_set_inf (mpc_realref (rop), +1); |
| else |
| |
| mpfr_set_nan (mpc_realref (rop)); |
| mpfr_set_nan (mpc_imagref (rop)); |
| inex_im = 0; |
| } |
| else |
| { |
| |
| if (mpfr_inf_p (mpc_realref (op)) && mpfr_signbit (mpc_realref (op)) |
| == 0 && mpfr_number_p (mpc_imagref (op))) |
| inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), |
| mpc_realref (op), MPC_RND_IM (rnd)); |
| else |
| |
| |
| inex_im = mpc_log10_aux (rop, op, rnd, 1, 0); |
| mpfr_set_inf (mpc_realref (rop), +1); |
| } |
| return MPC_INEX(0, inex_im); |
| } |
| |
| |
| re_cmp = mpfr_cmp_ui (mpc_realref (op), 0); |
| im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0); |
| if (im_cmp == 0) |
| { |
| if (re_cmp == 0) |
| { |
| if (mpfr_signbit (mpc_realref (op)) == 0) |
| inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), |
| mpc_realref (op), MPC_RND_IM (rnd)); |
| else |
| inex_im = mpc_log10_aux (rop, op, rnd, 1, 0); |
| mpfr_set_inf (mpc_realref (rop), -1); |
| inex_re = 0; |
| } |
| else if (re_cmp > 0) |
| { |
| inex_re = mpfr_log10 (mpc_realref (rop), mpc_realref (op), |
| MPC_RND_RE (rnd)); |
| inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op), |
| MPC_RND_IM (rnd)); |
| } |
| else |
| { |
| negative_zero = mpfr_signbit (mpc_imagref (op)); |
| if (negative_zero) |
| rnd_im = INV_RND (MPC_RND_IM (rnd)); |
| else |
| rnd_im = MPC_RND_IM (rnd); |
| ww->re[0] = *mpc_realref (op); |
| MPFR_CHANGE_SIGN (ww->re); |
| ww->im[0] = *mpc_imagref (op); |
| if (mpfr_cmp_ui (ww->re, 1) == 0) |
| inex_re = mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd)); |
| else |
| inex_re = mpc_log10_aux (rop, ww, rnd, 0, 1); |
| inex_im = mpc_log10_aux (rop, op, MPC_RND (0,rnd_im), 1, 2); |
| if (negative_zero) |
| { |
| mpc_conj (rop, rop, MPC_RNDNN); |
| inex_im = -inex_im; |
| } |
| } |
| return MPC_INEX(inex_re, inex_im); |
| } |
| else if (re_cmp == 0) |
| { |
| if (im_cmp > 0) |
| { |
| inex_re = mpfr_log10 (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE (rnd)); |
| inex_im = mpc_log10_aux (rop, op, rnd, 1, 2); |
| |
| mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN); |
| } |
| else |
| { |
| w [0] = *mpc_imagref (op); |
| MPFR_CHANGE_SIGN (w); |
| inex_re = mpfr_log10 (mpc_realref (rop), w, MPC_RND_RE (rnd)); |
| invrnd = MPC_RND (0, INV_RND (MPC_RND_IM (rnd))); |
| inex_im = mpc_log10_aux (rop, op, invrnd, 1, 2); |
| |
| mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN); |
| mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN); |
| inex_im = -inex_im; |
| } |
| return MPC_INEX(inex_re, inex_im); |
| } |
| |
| |
| prec = MPC_PREC_RE(rop); |
| mpfr_init2 (w, prec); |
| mpc_init2 (ww, prec); |
| |
| while (ok == 0) |
| { |
| loops ++; |
| prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2; |
| mpfr_set_prec (w, prec); |
| mpc_set_prec (ww, prec); |
| |
| mpc_log (ww, op, MPC_RNDNN); |
| mpfr_set_ui (w, 10, GMP_RNDN); |
| mpfr_log (w, w, GMP_RNDN); |
| mpc_div_fr (ww, ww, w, MPC_RNDNN); |
| |
| ok = mpfr_can_round (mpc_realref (ww), prec - 2, GMP_RNDN, GMP_RNDZ, |
| MPC_PREC_RE(rop) + (MPC_RND_RE (rnd) == GMP_RNDN)); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if ((ok == 0) && (loops == 1) && mpfr_integer_p (mpc_realref (op)) && |
| mpfr_integer_p (mpc_imagref (op))) |
| { |
| mpz_t x, y; |
| unsigned long s, v; |
| |
| mpz_init (x); |
| mpz_init (y); |
| mpfr_get_z (x, mpc_realref (op), GMP_RNDN); |
| mpfr_get_z (y, mpc_imagref (op), GMP_RNDN); |
| mpz_mul (x, x, x); |
| mpz_mul (y, y, y); |
| mpz_add (x, x, y); |
| v = mpz_scan1 (x, 0); |
| |
| s = mpz_sizeinbase (x, 10); |
| |
| |
| if (s == v + 1 || s == v + 2) |
| { |
| mpz_div_2exp (x, x, v); |
| mpz_ui_pow_ui (y, 5, v); |
| if (mpz_cmp (y, x) == 0) |
| { |
| |
| |
| mpfr_set_prec (mpc_realref (ww), sizeof(unsigned long)*CHAR_BIT); |
| mpfr_set_ui_2exp (mpc_realref (ww), v, -1, GMP_RNDN); |
| ok = 1; |
| } |
| } |
| mpz_clear (x); |
| mpz_clear (y); |
| } |
| |
| ok = ok && mpfr_can_round (mpc_imagref (ww), prec-2, GMP_RNDN, GMP_RNDZ, |
| MPC_PREC_IM(rop) + (MPC_RND_IM (rnd) == GMP_RNDN)); |
| } |
| |
| inex_re = mpfr_set (mpc_realref(rop), mpc_realref (ww), MPC_RND_RE (rnd)); |
| inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref (ww), MPC_RND_IM (rnd)); |
| mpfr_clear (w); |
| mpc_clear (ww); |
| return MPC_INEX(inex_re, inex_im); |
| } |