|
Packit Service |
2e9770 |
/* mpc_log10 -- Take the base-10 logarithm of a complex number.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
Copyright (C) 2012 INRIA
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
This file is part of GNU MPC.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
GNU MPC is free software; you can redistribute it and/or modify it under
|
|
Packit Service |
2e9770 |
the terms of the GNU Lesser General Public License as published by the
|
|
Packit Service |
2e9770 |
Free Software Foundation; either version 3 of the License, or (at your
|
|
Packit Service |
2e9770 |
option) any later version.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
Packit Service |
2e9770 |
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
Packit Service |
2e9770 |
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
Packit Service |
2e9770 |
more details.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
2e9770 |
along with this program. If not, see http://logw.gnu.org/licenses/ .
|
|
Packit Service |
2e9770 |
*/
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
#include <limits.h> /* for CHAR_BIT */
|
|
Packit Service |
2e9770 |
#include "mpc-impl.h"
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
static void
|
|
Packit Service |
2e9770 |
mpfr_const_log10 (mpfr_ptr log10)
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_set_ui (log10, 10, MPFR_RNDN); /* exact since prec >= 4 */
|
|
Packit Service |
2e9770 |
mpfr_log (log10, log10, MPFR_RNDN); /* error <= 1/2 ulp */
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
int
|
|
Packit Service |
2e9770 |
mpc_log10 (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
int ok = 0, loops = 0, check_exact = 0, special_re, special_im,
|
|
Packit Service |
2e9770 |
inex, inex_re, inex_im;
|
|
Packit Service |
2e9770 |
mpfr_prec_t prec;
|
|
Packit Service |
2e9770 |
mpfr_t log10;
|
|
Packit Service |
2e9770 |
mpc_t log;
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
mpfr_init2 (log10, 2);
|
|
Packit Service |
2e9770 |
mpc_init2 (log, 2);
|
|
Packit Service |
2e9770 |
prec = MPC_MAX_PREC (rop);
|
|
Packit Service |
2e9770 |
/* compute log(op)/log(10) */
|
|
Packit Service |
2e9770 |
while (ok == 0) {
|
|
Packit Service |
2e9770 |
loops ++;
|
|
Packit Service |
2e9770 |
prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2;
|
|
Packit Service |
2e9770 |
mpfr_set_prec (log10, prec);
|
|
Packit Service |
2e9770 |
mpc_set_prec (log, prec);
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
inex = mpc_log (log, op, rnd); /* error <= 1 ulp */
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
if (!mpfr_number_p (mpc_imagref (log))
|
|
Packit Service |
2e9770 |
|| mpfr_zero_p (mpc_imagref (log))) {
|
|
Packit Service |
2e9770 |
/* no need to divide by log(10) */
|
|
Packit Service |
2e9770 |
special_im = 1;
|
|
Packit Service |
2e9770 |
ok = 1;
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
else {
|
|
Packit Service |
2e9770 |
special_im = 0;
|
|
Packit Service |
2e9770 |
mpfr_const_log10 (log10);
|
|
Packit Service |
2e9770 |
mpfr_div (mpc_imagref (log), mpc_imagref (log), log10, MPFR_RNDN);
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
ok = mpfr_can_round (mpc_imagref (log), prec - 2,
|
|
Packit Service |
2e9770 |
MPFR_RNDN, MPFR_RNDZ,
|
|
Packit Service |
2e9770 |
MPC_PREC_IM(rop) + (MPC_RND_IM (rnd) == MPFR_RNDN));
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
if (ok) {
|
|
Packit Service |
2e9770 |
if (!mpfr_number_p (mpc_realref (log))
|
|
Packit Service |
2e9770 |
|| mpfr_zero_p (mpc_realref (log)))
|
|
Packit Service |
2e9770 |
special_re = 1;
|
|
Packit Service |
2e9770 |
else {
|
|
Packit Service |
2e9770 |
special_re = 0;
|
|
Packit Service |
2e9770 |
if (special_im)
|
|
Packit Service |
2e9770 |
/* log10 not yet computed */
|
|
Packit Service |
2e9770 |
mpfr_const_log10 (log10);
|
|
Packit Service |
2e9770 |
mpfr_div (mpc_realref (log), mpc_realref (log), log10, MPFR_RNDN);
|
|
Packit Service |
2e9770 |
/* error <= 24/7 ulp < 4 ulp for prec >= 4, see algorithms.tex */
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
ok = mpfr_can_round (mpc_realref (log), prec - 2,
|
|
Packit Service |
2e9770 |
MPFR_RNDN, MPFR_RNDZ,
|
|
Packit Service |
2e9770 |
MPC_PREC_RE(rop) + (MPC_RND_RE (rnd) == MPFR_RNDN));
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
/* Special code to deal with cases where the real part of log10(x+i*y)
|
|
Packit Service |
2e9770 |
is exact, like x=3 and y=1. Since Re(log10(x+i*y)) = log10(x^2+y^2)/2
|
|
Packit Service |
2e9770 |
this happens whenever x^2+y^2 is a nonnegative power of 10.
|
|
Packit Service |
2e9770 |
Indeed x^2+y^2 cannot equal 10^(a/2^b) for a, b integers, a odd, b>0,
|
|
Packit Service |
2e9770 |
since x^2+y^2 is rational, and 10^(a/2^b) is irrational.
|
|
Packit Service |
2e9770 |
Similarly, for b=0, x^2+y^2 cannot equal 10^a for a < 0 since x^2+y^2
|
|
Packit Service |
2e9770 |
is a rational with denominator a power of 2.
|
|
Packit Service |
2e9770 |
Now let x^2+y^2 = 10^s. Without loss of generality we can assume
|
|
Packit Service |
2e9770 |
x = u/2^e and y = v/2^e with u, v, e integers: u^2+v^2 = 10^s*2^(2e)
|
|
Packit Service |
2e9770 |
thus u^2+v^2 = 0 mod 2^(2e). By recurrence on e, necessarily
|
|
Packit Service |
2e9770 |
u = v = 0 mod 2^e, thus x and y are necessarily integers.
|
|
Packit Service |
2e9770 |
*/
|
|
Packit Service |
2e9770 |
if (!ok && !check_exact && mpfr_integer_p (mpc_realref (op)) &&
|
|
Packit Service |
2e9770 |
mpfr_integer_p (mpc_imagref (op))) {
|
|
Packit Service |
2e9770 |
mpz_t x, y;
|
|
Packit Service |
2e9770 |
unsigned long s, v;
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
check_exact = 1;
|
|
Packit Service |
2e9770 |
mpz_init (x);
|
|
Packit Service |
2e9770 |
mpz_init (y);
|
|
Packit Service |
2e9770 |
mpfr_get_z (x, mpc_realref (op), MPFR_RNDN); /* exact */
|
|
Packit Service |
2e9770 |
mpfr_get_z (y, mpc_imagref (op), MPFR_RNDN); /* exact */
|
|
Packit Service |
2e9770 |
mpz_mul (x, x, x);
|
|
Packit Service |
2e9770 |
mpz_mul (y, y, y);
|
|
Packit Service |
2e9770 |
mpz_add (x, x, y); /* x^2+y^2 */
|
|
Packit Service |
2e9770 |
v = mpz_scan1 (x, 0);
|
|
Packit Service |
2e9770 |
/* if x = 10^s then necessarily s = v */
|
|
Packit Service |
2e9770 |
s = mpz_sizeinbase (x, 10);
|
|
Packit Service |
2e9770 |
/* since s is either the number of digits of x or one more,
|
|
Packit Service |
2e9770 |
then x = 10^(s-1) or 10^(s-2) */
|
|
Packit Service |
2e9770 |
if (s == v + 1 || s == v + 2) {
|
|
Packit Service |
2e9770 |
mpz_div_2exp (x, x, v);
|
|
Packit Service |
2e9770 |
mpz_ui_pow_ui (y, 5, v);
|
|
Packit Service |
2e9770 |
if (mpz_cmp (y, x) == 0) {
|
|
Packit Service |
2e9770 |
/* Re(log10(x+i*y)) is exactly v/2
|
|
Packit Service |
2e9770 |
we reset the precision of Re(log) so that v can be
|
|
Packit Service |
2e9770 |
represented exactly */
|
|
Packit Service |
2e9770 |
mpfr_set_prec (mpc_realref (log),
|
|
Packit Service |
2e9770 |
sizeof(unsigned long)*CHAR_BIT);
|
|
Packit Service |
2e9770 |
mpfr_set_ui_2exp (mpc_realref (log), v, -1, MPFR_RNDN);
|
|
Packit Service |
2e9770 |
/* exact */
|
|
Packit Service |
2e9770 |
ok = 1;
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
mpz_clear (x);
|
|
Packit Service |
2e9770 |
mpz_clear (y);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
inex_re = mpfr_set (mpc_realref(rop), mpc_realref (log), MPC_RND_RE (rnd));
|
|
Packit Service |
2e9770 |
if (special_re)
|
|
Packit Service |
2e9770 |
inex_re = MPC_INEX_RE (inex);
|
|
Packit Service |
2e9770 |
/* recover flag from call to mpc_log above */
|
|
Packit Service |
2e9770 |
inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref (log), MPC_RND_IM (rnd));
|
|
Packit Service |
2e9770 |
if (special_im)
|
|
Packit Service |
2e9770 |
inex_im = MPC_INEX_IM (inex);
|
|
Packit Service |
2e9770 |
mpfr_clear (log10);
|
|
Packit Service |
2e9770 |
mpc_clear (log);
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
return MPC_INEX(inex_re, inex_im);
|
|
Packit Service |
2e9770 |
}
|