|
Packit Service |
2e9770 |
/* mpc_asin -- arcsine of a complex number.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
Copyright (C) INRIA, 2009, 2010
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
This file is part of the MPC Library.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
The MPC Library is free software; you can redistribute it and/or modify
|
|
Packit Service |
2e9770 |
it under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
2e9770 |
the Free Software Foundation; either version 2.1 of the License, or (at your
|
|
Packit Service |
2e9770 |
option) any later version.
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
The MPC Library is distributed in the hope that it will be useful, but
|
|
Packit Service |
2e9770 |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit Service |
2e9770 |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
Packit Service |
2e9770 |
License for 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 the MPC Library; see the file COPYING.LIB. If not, write to
|
|
Packit Service |
2e9770 |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
Packit Service |
2e9770 |
MA 02111-1307, USA. */
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
#include "mpc-impl.h"
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
int
|
|
Packit Service |
2e9770 |
mpc_asin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_prec_t p, p_re, p_im, incr_p = 0;
|
|
Packit Service |
2e9770 |
mpfr_rnd_t rnd_re, rnd_im;
|
|
Packit Service |
2e9770 |
mpc_t z1;
|
|
Packit Service |
2e9770 |
int inex;
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
/* special values */
|
|
Packit Service |
2e9770 |
if (mpfr_nan_p (MPC_RE (op)) || mpfr_nan_p (MPC_IM (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
if (mpfr_inf_p (MPC_RE (op)) || mpfr_inf_p (MPC_IM (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_set_nan (MPC_RE (rop));
|
|
Packit Service |
2e9770 |
mpfr_set_inf (MPC_IM (rop), mpfr_signbit (MPC_IM (op)) ? -1 : +1);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
else if (mpfr_zero_p (MPC_RE (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_set (MPC_RE (rop), MPC_RE (op), GMP_RNDN);
|
|
Packit Service |
2e9770 |
mpfr_set_nan (MPC_IM (rop));
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
else
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_set_nan (MPC_RE (rop));
|
|
Packit Service |
2e9770 |
mpfr_set_nan (MPC_IM (rop));
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
return 0;
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
if (mpfr_inf_p (MPC_RE (op)) || mpfr_inf_p (MPC_IM (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
int inex_re;
|
|
Packit Service |
2e9770 |
if (mpfr_inf_p (MPC_RE (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
inex_re = set_pi_over_2 (MPC_RE (rop), -mpfr_signbit (MPC_RE (op)),
|
|
Packit Service |
2e9770 |
MPC_RND_RE (rnd));
|
|
Packit Service |
2e9770 |
mpfr_set_inf (MPC_IM (rop), -mpfr_signbit (MPC_IM (op)));
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
if (mpfr_inf_p (MPC_IM (op)))
|
|
Packit Service |
2e9770 |
mpfr_div_2ui (MPC_RE (rop), MPC_RE (rop), 1, GMP_RNDN);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
else
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
int s;
|
|
Packit Service |
2e9770 |
s = mpfr_signbit (MPC_RE (op));
|
|
Packit Service |
2e9770 |
inex_re = mpfr_set_ui (MPC_RE (rop), 0, GMP_RNDN);
|
|
Packit Service |
2e9770 |
if (s)
|
|
Packit Service |
2e9770 |
mpfr_neg (MPC_RE (rop), MPC_RE (rop), GMP_RNDN);
|
|
Packit Service |
2e9770 |
mpfr_set_inf (MPC_IM (rop), -mpfr_signbit (MPC_IM (op)));
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
return MPC_INEX (inex_re, 0);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
/* pure real argument */
|
|
Packit Service |
2e9770 |
if (mpfr_zero_p (MPC_IM (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
int inex_re;
|
|
Packit Service |
2e9770 |
int inex_im;
|
|
Packit Service |
2e9770 |
int s_im;
|
|
Packit Service |
2e9770 |
s_im = mpfr_signbit (MPC_IM (op));
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
if (mpfr_cmp_ui (MPC_RE (op), 1) > 0)
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
if (s_im)
|
|
Packit Service |
2e9770 |
inex_im = -mpfr_acosh (MPC_IM (rop), MPC_RE (op),
|
|
Packit Service |
2e9770 |
INV_RND (MPC_RND_IM (rnd)));
|
|
Packit Service |
2e9770 |
else
|
|
Packit Service |
2e9770 |
inex_im = mpfr_acosh (MPC_IM (rop), MPC_RE (op),
|
|
Packit Service |
2e9770 |
MPC_RND_IM (rnd));
|
|
Packit Service |
2e9770 |
inex_re = set_pi_over_2 (MPC_RE (rop), -mpfr_signbit (MPC_RE (op)),
|
|
Packit Service |
2e9770 |
MPC_RND_RE (rnd));
|
|
Packit Service |
2e9770 |
if (s_im)
|
|
Packit Service |
2e9770 |
mpc_conj (rop, rop, MPC_RNDNN);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
else if (mpfr_cmp_si (MPC_RE (op), -1) < 0)
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_t minus_op_re;
|
|
Packit Service |
2e9770 |
minus_op_re[0] = MPC_RE (op)[0];
|
|
Packit Service |
2e9770 |
MPFR_CHANGE_SIGN (minus_op_re);
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
if (s_im)
|
|
Packit Service |
2e9770 |
inex_im = -mpfr_acosh (MPC_IM (rop), minus_op_re,
|
|
Packit Service |
2e9770 |
INV_RND (MPC_RND_IM (rnd)));
|
|
Packit Service |
2e9770 |
else
|
|
Packit Service |
2e9770 |
inex_im = mpfr_acosh (MPC_IM (rop), minus_op_re,
|
|
Packit Service |
2e9770 |
MPC_RND_IM (rnd));
|
|
Packit Service |
2e9770 |
inex_re = set_pi_over_2 (MPC_RE (rop), -mpfr_signbit (MPC_RE (op)),
|
|
Packit Service |
2e9770 |
MPC_RND_RE (rnd));
|
|
Packit Service |
2e9770 |
if (s_im)
|
|
Packit Service |
2e9770 |
mpc_conj (rop, rop, MPC_RNDNN);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
else
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
inex_im = mpfr_set_ui (MPC_IM (rop), 0, MPC_RND_IM (rnd));
|
|
Packit Service |
2e9770 |
if (s_im)
|
|
Packit Service |
2e9770 |
mpfr_neg (MPC_IM (rop), MPC_IM (rop), GMP_RNDN);
|
|
Packit Service |
2e9770 |
inex_re = mpfr_asin (MPC_RE (rop), MPC_RE (op), MPC_RND_RE (rnd));
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
return MPC_INEX (inex_re, inex_im);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
/* pure imaginary argument */
|
|
Packit Service |
2e9770 |
if (mpfr_zero_p (MPC_RE (op)))
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
int inex_im;
|
|
Packit Service |
2e9770 |
int s;
|
|
Packit Service |
2e9770 |
s = mpfr_signbit (MPC_RE (op));
|
|
Packit Service |
2e9770 |
mpfr_set_ui (MPC_RE (rop), 0, GMP_RNDN);
|
|
Packit Service |
2e9770 |
if (s)
|
|
Packit Service |
2e9770 |
mpfr_neg (MPC_RE (rop), MPC_RE (rop), GMP_RNDN);
|
|
Packit Service |
2e9770 |
inex_im = mpfr_asinh (MPC_IM (rop), MPC_IM (op), MPC_RND_IM (rnd));
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
return MPC_INEX (0, inex_im);
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
/* regular complex: asin(z) = -i*log(i*z+sqrt(1-z^2)) */
|
|
Packit Service |
2e9770 |
p_re = mpfr_get_prec (MPC_RE(rop));
|
|
Packit Service |
2e9770 |
p_im = mpfr_get_prec (MPC_IM(rop));
|
|
Packit Service |
2e9770 |
rnd_re = MPC_RND_RE(rnd);
|
|
Packit Service |
2e9770 |
rnd_im = MPC_RND_IM(rnd);
|
|
Packit Service |
2e9770 |
p = p_re >= p_im ? p_re : p_im;
|
|
Packit Service |
2e9770 |
mpc_init2 (z1, p);
|
|
Packit Service |
2e9770 |
while (1)
|
|
Packit Service |
2e9770 |
{
|
|
Packit Service |
2e9770 |
mpfr_exp_t ex, ey, err;
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
p += mpc_ceil_log2 (p) + 3 + incr_p; /* incr_p is zero initially */
|
|
Packit Service |
2e9770 |
incr_p = p / 2;
|
|
Packit Service |
2e9770 |
mpfr_set_prec (MPC_RE(z1), p);
|
|
Packit Service |
2e9770 |
mpfr_set_prec (MPC_IM(z1), p);
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
/* z1 <- z^2 */
|
|
Packit Service |
2e9770 |
mpc_sqr (z1, op, MPC_RNDNN);
|
|
Packit Service |
2e9770 |
/* err(x) <= 1/2 ulp(x), err(y) <= 1/2 ulp(y) */
|
|
Packit Service |
2e9770 |
/* z1 <- 1-z1 */
|
|
Packit Service |
2e9770 |
ex = mpfr_get_exp (MPC_RE(z1));
|
|
Packit Service |
2e9770 |
mpfr_ui_sub (MPC_RE(z1), 1, MPC_RE(z1), GMP_RNDN);
|
|
Packit Service |
2e9770 |
mpfr_neg (MPC_IM(z1), MPC_IM(z1), GMP_RNDN);
|
|
Packit Service |
2e9770 |
ex = ex - mpfr_get_exp (MPC_RE(z1));
|
|
Packit Service |
2e9770 |
ex = (ex <= 0) ? 0 : ex;
|
|
Packit Service |
2e9770 |
/* err(x) <= 2^ex * ulp(x) */
|
|
Packit Service |
2e9770 |
ex = ex + mpfr_get_exp (MPC_RE(z1)) - p;
|
|
Packit Service |
2e9770 |
/* err(x) <= 2^ex */
|
|
Packit Service |
2e9770 |
ey = mpfr_get_exp (MPC_IM(z1)) - p - 1;
|
|
Packit Service |
2e9770 |
/* err(y) <= 2^ey */
|
|
Packit Service |
2e9770 |
ex = (ex >= ey) ? ex : ey; /* err(x), err(y) <= 2^ex, i.e., the norm
|
|
Packit Service |
2e9770 |
of the error is bounded by |h|<=2^(ex+1/2) */
|
|
Packit Service |
2e9770 |
/* z1 <- sqrt(z1): if z1 = z + h, then sqrt(z1) = sqrt(z) + h/2/sqrt(t) */
|
|
Packit Service |
2e9770 |
ey = mpfr_get_exp (MPC_RE(z1)) >= mpfr_get_exp (MPC_IM(z1))
|
|
Packit Service |
2e9770 |
? mpfr_get_exp (MPC_RE(z1)) : mpfr_get_exp (MPC_IM(z1));
|
|
Packit Service |
2e9770 |
/* we have |z1| >= 2^(ey-1) thus 1/|z1| <= 2^(1-ey) */
|
|
Packit Service |
2e9770 |
mpc_sqrt (z1, z1, MPC_RNDNN);
|
|
Packit Service |
2e9770 |
ex = (2 * ex + 1) - 2 - (ey - 1); /* |h^2/4/|t| <= 2^ex */
|
|
Packit Service |
2e9770 |
ex = (ex + 1) / 2; /* ceil(ex/2) */
|
|
Packit Service |
2e9770 |
/* express ex in terms of ulp(z1) */
|
|
Packit Service |
2e9770 |
ey = mpfr_get_exp (MPC_RE(z1)) <= mpfr_get_exp (MPC_IM(z1))
|
|
Packit Service |
2e9770 |
? mpfr_get_exp (MPC_RE(z1)) : mpfr_get_exp (MPC_IM(z1));
|
|
Packit Service |
2e9770 |
ex = ex - ey + p;
|
|
Packit Service |
2e9770 |
/* take into account the rounding error in the mpc_sqrt call */
|
|
Packit Service |
2e9770 |
err = (ex <= 0) ? 1 : ex + 1;
|
|
Packit Service |
2e9770 |
/* err(x) <= 2^err * ulp(x), err(y) <= 2^err * ulp(y) */
|
|
Packit Service |
2e9770 |
/* z1 <- i*z + z1 */
|
|
Packit Service |
2e9770 |
ex = mpfr_get_exp (MPC_RE(z1));
|
|
Packit Service |
2e9770 |
ey = mpfr_get_exp (MPC_IM(z1));
|
|
Packit Service |
2e9770 |
mpfr_sub (MPC_RE(z1), MPC_RE(z1), MPC_IM(op), GMP_RNDN);
|
|
Packit Service |
2e9770 |
mpfr_add (MPC_IM(z1), MPC_IM(z1), MPC_RE(op), GMP_RNDN);
|
|
Packit Service |
2e9770 |
if (mpfr_cmp_ui (MPC_RE(z1), 0) == 0 || mpfr_cmp_ui (MPC_IM(z1), 0) == 0)
|
|
Packit Service |
2e9770 |
continue;
|
|
Packit Service |
2e9770 |
ex -= mpfr_get_exp (MPC_RE(z1)); /* cancellation in x */
|
|
Packit Service |
2e9770 |
ey -= mpfr_get_exp (MPC_IM(z1)); /* cancellation in y */
|
|
Packit Service |
2e9770 |
ex = (ex >= ey) ? ex : ey; /* maximum cancellation */
|
|
Packit Service |
2e9770 |
err += ex;
|
|
Packit Service |
2e9770 |
err = (err <= 0) ? 1 : err + 1; /* rounding error in sub/add */
|
|
Packit Service |
2e9770 |
/* z1 <- log(z1): if z1 = z + h, then log(z1) = log(z) + h/t with
|
|
Packit Service |
2e9770 |
|t| >= min(|z1|,|z|) */
|
|
Packit Service |
2e9770 |
ex = mpfr_get_exp (MPC_RE(z1));
|
|
Packit Service |
2e9770 |
ey = mpfr_get_exp (MPC_IM(z1));
|
|
Packit Service |
2e9770 |
ex = (ex >= ey) ? ex : ey;
|
|
Packit Service |
2e9770 |
err += ex - p; /* revert to absolute error <= 2^err */
|
|
Packit Service |
2e9770 |
mpc_log (z1, z1, GMP_RNDN);
|
|
Packit Service |
2e9770 |
err -= ex - 1; /* 1/|t| <= 1/|z| <= 2^(1-ex) */
|
|
Packit Service |
2e9770 |
/* express err in terms of ulp(z1) */
|
|
Packit Service |
2e9770 |
ey = mpfr_get_exp (MPC_RE(z1)) <= mpfr_get_exp (MPC_IM(z1))
|
|
Packit Service |
2e9770 |
? mpfr_get_exp (MPC_RE(z1)) : mpfr_get_exp (MPC_IM(z1));
|
|
Packit Service |
2e9770 |
err = err - ey + p;
|
|
Packit Service |
2e9770 |
/* take into account the rounding error in the mpc_log call */
|
|
Packit Service |
2e9770 |
err = (err <= 0) ? 1 : err + 1;
|
|
Packit Service |
2e9770 |
/* z1 <- -i*z1 */
|
|
Packit Service |
2e9770 |
mpfr_swap (MPC_RE(z1), MPC_IM(z1));
|
|
Packit Service |
2e9770 |
mpfr_neg (MPC_IM(z1), MPC_IM(z1), GMP_RNDN);
|
|
Packit Service |
2e9770 |
if (mpfr_can_round (MPC_RE(z1), p - err, GMP_RNDN, GMP_RNDZ,
|
|
Packit Service |
2e9770 |
p_re + (rnd_re == GMP_RNDN)) &&
|
|
Packit Service |
2e9770 |
mpfr_can_round (MPC_IM(z1), p - err, GMP_RNDN, GMP_RNDZ,
|
|
Packit Service |
2e9770 |
p_im + (rnd_im == GMP_RNDN)))
|
|
Packit Service |
2e9770 |
break;
|
|
Packit Service |
2e9770 |
}
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
inex = mpc_set (rop, z1, rnd);
|
|
Packit Service |
2e9770 |
mpc_clear (z1);
|
|
Packit Service |
2e9770 |
|
|
Packit Service |
2e9770 |
return inex;
|
|
Packit Service |
2e9770 |
}
|