18fa80f29Smrg /* mpc_log10 -- Take the base-10 logarithm of a complex number.
28fa80f29Smrg
3*90a8ff21Smrg Copyright (C) 2012, 2020 INRIA
48fa80f29Smrg
58fa80f29Smrg This file is part of GNU MPC.
68fa80f29Smrg
78fa80f29Smrg GNU MPC is free software; you can redistribute it and/or modify it under
88fa80f29Smrg the terms of the GNU Lesser General Public License as published by the
98fa80f29Smrg Free Software Foundation; either version 3 of the License, or (at your
108fa80f29Smrg option) any later version.
118fa80f29Smrg
128fa80f29Smrg GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
138fa80f29Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
148fa80f29Smrg FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
158fa80f29Smrg more details.
168fa80f29Smrg
178fa80f29Smrg You should have received a copy of the GNU Lesser General Public License
1839f28e1eSmrg along with this program. If not, see http://logw.gnu.org/licenses/ .
198fa80f29Smrg */
208fa80f29Smrg
218fa80f29Smrg #include <limits.h> /* for CHAR_BIT */
228fa80f29Smrg #include "mpc-impl.h"
238fa80f29Smrg
2439f28e1eSmrg static void
mpfr_const_log10(mpfr_ptr log10)2539f28e1eSmrg mpfr_const_log10 (mpfr_ptr log10)
268fa80f29Smrg {
2739f28e1eSmrg mpfr_set_ui (log10, 10, MPFR_RNDN); /* exact since prec >= 4 */
2839f28e1eSmrg mpfr_log (log10, log10, MPFR_RNDN); /* error <= 1/2 ulp */
2939f28e1eSmrg }
308fa80f29Smrg
318fa80f29Smrg
328fa80f29Smrg int
mpc_log10(mpc_ptr rop,mpc_srcptr op,mpc_rnd_t rnd)338fa80f29Smrg mpc_log10 (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
348fa80f29Smrg {
3539f28e1eSmrg int ok = 0, loops = 0, check_exact = 0, special_re, special_im,
3639f28e1eSmrg inex, inex_re, inex_im;
378fa80f29Smrg mpfr_prec_t prec;
3839f28e1eSmrg mpfr_t log10;
3939f28e1eSmrg mpc_t log;
40*90a8ff21Smrg mpfr_exp_t saved_emin, saved_emax;
41*90a8ff21Smrg
42*90a8ff21Smrg saved_emin = mpfr_get_emin ();
43*90a8ff21Smrg saved_emax = mpfr_get_emax ();
44*90a8ff21Smrg mpfr_set_emin (mpfr_get_emin_min ());
45*90a8ff21Smrg mpfr_set_emax (mpfr_get_emax_max ());
468fa80f29Smrg
4739f28e1eSmrg mpfr_init2 (log10, 2);
4839f28e1eSmrg mpc_init2 (log, 2);
4939f28e1eSmrg prec = MPC_MAX_PREC (rop);
5039f28e1eSmrg /* compute log(op)/log(10) */
5139f28e1eSmrg while (ok == 0) {
528fa80f29Smrg loops ++;
538fa80f29Smrg prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2;
5439f28e1eSmrg mpfr_set_prec (log10, prec);
5539f28e1eSmrg mpc_set_prec (log, prec);
568fa80f29Smrg
5739f28e1eSmrg inex = mpc_log (log, op, rnd); /* error <= 1 ulp */
588fa80f29Smrg
5939f28e1eSmrg if (!mpfr_number_p (mpc_imagref (log))
6039f28e1eSmrg || mpfr_zero_p (mpc_imagref (log))) {
6139f28e1eSmrg /* no need to divide by log(10) */
6239f28e1eSmrg special_im = 1;
6339f28e1eSmrg ok = 1;
6439f28e1eSmrg }
6539f28e1eSmrg else {
6639f28e1eSmrg special_im = 0;
6739f28e1eSmrg mpfr_const_log10 (log10);
6839f28e1eSmrg mpfr_div (mpc_imagref (log), mpc_imagref (log), log10, MPFR_RNDN);
6939f28e1eSmrg
7039f28e1eSmrg ok = mpfr_can_round (mpc_imagref (log), prec - 2,
7139f28e1eSmrg MPFR_RNDN, MPFR_RNDZ,
7239f28e1eSmrg MPC_PREC_IM(rop) + (MPC_RND_IM (rnd) == MPFR_RNDN));
7339f28e1eSmrg }
7439f28e1eSmrg
7539f28e1eSmrg if (ok) {
7639f28e1eSmrg if (!mpfr_number_p (mpc_realref (log))
7739f28e1eSmrg || mpfr_zero_p (mpc_realref (log)))
7839f28e1eSmrg special_re = 1;
7939f28e1eSmrg else {
8039f28e1eSmrg special_re = 0;
8139f28e1eSmrg if (special_im)
8239f28e1eSmrg /* log10 not yet computed */
8339f28e1eSmrg mpfr_const_log10 (log10);
8439f28e1eSmrg mpfr_div (mpc_realref (log), mpc_realref (log), log10, MPFR_RNDN);
8539f28e1eSmrg /* error <= 24/7 ulp < 4 ulp for prec >= 4, see algorithms.tex */
8639f28e1eSmrg
8739f28e1eSmrg ok = mpfr_can_round (mpc_realref (log), prec - 2,
8839f28e1eSmrg MPFR_RNDN, MPFR_RNDZ,
8939f28e1eSmrg MPC_PREC_RE(rop) + (MPC_RND_RE (rnd) == MPFR_RNDN));
9039f28e1eSmrg }
918fa80f29Smrg
928fa80f29Smrg /* Special code to deal with cases where the real part of log10(x+i*y)
938fa80f29Smrg is exact, like x=3 and y=1. Since Re(log10(x+i*y)) = log10(x^2+y^2)/2
948fa80f29Smrg this happens whenever x^2+y^2 is a nonnegative power of 10.
958fa80f29Smrg Indeed x^2+y^2 cannot equal 10^(a/2^b) for a, b integers, a odd, b>0,
968fa80f29Smrg since x^2+y^2 is rational, and 10^(a/2^b) is irrational.
978fa80f29Smrg Similarly, for b=0, x^2+y^2 cannot equal 10^a for a < 0 since x^2+y^2
988fa80f29Smrg is a rational with denominator a power of 2.
998fa80f29Smrg Now let x^2+y^2 = 10^s. Without loss of generality we can assume
1008fa80f29Smrg x = u/2^e and y = v/2^e with u, v, e integers: u^2+v^2 = 10^s*2^(2e)
1018fa80f29Smrg thus u^2+v^2 = 0 mod 2^(2e). By recurrence on e, necessarily
1028fa80f29Smrg u = v = 0 mod 2^e, thus x and y are necessarily integers.
1038fa80f29Smrg */
10439f28e1eSmrg if (!ok && !check_exact && mpfr_integer_p (mpc_realref (op)) &&
10539f28e1eSmrg mpfr_integer_p (mpc_imagref (op))) {
1068fa80f29Smrg mpz_t x, y;
1078fa80f29Smrg unsigned long s, v;
1088fa80f29Smrg
10939f28e1eSmrg check_exact = 1;
1108fa80f29Smrg mpz_init (x);
1118fa80f29Smrg mpz_init (y);
11239f28e1eSmrg mpfr_get_z (x, mpc_realref (op), MPFR_RNDN); /* exact */
11339f28e1eSmrg mpfr_get_z (y, mpc_imagref (op), MPFR_RNDN); /* exact */
1148fa80f29Smrg mpz_mul (x, x, x);
1158fa80f29Smrg mpz_mul (y, y, y);
1168fa80f29Smrg mpz_add (x, x, y); /* x^2+y^2 */
1178fa80f29Smrg v = mpz_scan1 (x, 0);
1188fa80f29Smrg /* if x = 10^s then necessarily s = v */
1198fa80f29Smrg s = mpz_sizeinbase (x, 10);
1208fa80f29Smrg /* since s is either the number of digits of x or one more,
1218fa80f29Smrg then x = 10^(s-1) or 10^(s-2) */
12239f28e1eSmrg if (s == v + 1 || s == v + 2) {
1238fa80f29Smrg mpz_div_2exp (x, x, v);
1248fa80f29Smrg mpz_ui_pow_ui (y, 5, v);
12539f28e1eSmrg if (mpz_cmp (y, x) == 0) {
12639f28e1eSmrg /* Re(log10(x+i*y)) is exactly v/2
12739f28e1eSmrg we reset the precision of Re(log) so that v can be
1288fa80f29Smrg represented exactly */
12939f28e1eSmrg mpfr_set_prec (mpc_realref (log),
13039f28e1eSmrg sizeof(unsigned long)*CHAR_BIT);
13139f28e1eSmrg mpfr_set_ui_2exp (mpc_realref (log), v, -1, MPFR_RNDN);
13239f28e1eSmrg /* exact */
1338fa80f29Smrg ok = 1;
1348fa80f29Smrg }
1358fa80f29Smrg }
1368fa80f29Smrg mpz_clear (x);
1378fa80f29Smrg mpz_clear (y);
1388fa80f29Smrg }
13939f28e1eSmrg }
1408fa80f29Smrg }
1418fa80f29Smrg
14239f28e1eSmrg inex_re = mpfr_set (mpc_realref(rop), mpc_realref (log), MPC_RND_RE (rnd));
14339f28e1eSmrg if (special_re)
14439f28e1eSmrg inex_re = MPC_INEX_RE (inex);
14539f28e1eSmrg /* recover flag from call to mpc_log above */
14639f28e1eSmrg inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref (log), MPC_RND_IM (rnd));
14739f28e1eSmrg if (special_im)
14839f28e1eSmrg inex_im = MPC_INEX_IM (inex);
14939f28e1eSmrg mpfr_clear (log10);
15039f28e1eSmrg mpc_clear (log);
15139f28e1eSmrg
152*90a8ff21Smrg /* restore the exponent range, and check the range of results */
153*90a8ff21Smrg mpfr_set_emin (saved_emin);
154*90a8ff21Smrg mpfr_set_emax (saved_emax);
155*90a8ff21Smrg inex_re = mpfr_check_range (mpc_realref (rop), inex_re, MPC_RND_RE (rnd));
156*90a8ff21Smrg inex_im = mpfr_check_range (mpc_imagref (rop), inex_im, MPC_RND_IM (rnd));
157*90a8ff21Smrg
1588fa80f29Smrg return MPC_INEX(inex_re, inex_im);
1598fa80f29Smrg }
160