mirror of
https://github.com/vale981/arb
synced 2025-03-05 17:31:38 -05:00
196 lines
3.9 KiB
C
196 lines
3.9 KiB
C
/*
|
|
Copyright (C) 2013 Fredrik Johansson
|
|
|
|
This file is part of Arb.
|
|
|
|
Arb is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU Lesser General Public License (LGPL) as published
|
|
by the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version. See <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "acb.h"
|
|
|
|
static void
|
|
_acb_rsqrt1(acb_t y, const acb_t x, slong prec)
|
|
{
|
|
#define a acb_realref(x)
|
|
#define b acb_imagref(x)
|
|
#define c acb_realref(y)
|
|
#define d acb_imagref(y)
|
|
|
|
arb_t r, t, u, v;
|
|
slong wp;
|
|
|
|
/* based on the identity sqrt(z) = sqrt(r) (z+r) / |z+r|: */
|
|
/* 1/sqrt(a+bi) = (1/v)((a+r) - b*i), r = |a+bi|, v = sqrt(r*(b^2+(a+r)^2)) */
|
|
|
|
wp = prec + 6;
|
|
|
|
arb_init(r);
|
|
arb_init(t);
|
|
arb_init(u);
|
|
arb_init(v);
|
|
|
|
/* u = b^2, r = |a+bi| */
|
|
arb_mul(t, a, a, wp);
|
|
arb_mul(u, b, b, wp);
|
|
arb_add(r, t, u, wp);
|
|
arb_sqrtpos(r, r, wp);
|
|
|
|
/* t = a+r, v = r*(b^2+(a+r)^2) */
|
|
arb_add(t, r, a, wp);
|
|
arb_mul(v, t, t, wp);
|
|
arb_add(v, v, u, wp);
|
|
arb_mul(v, v, r, wp);
|
|
|
|
/* v = 1/sqrt(v) */
|
|
arb_rsqrt(v, v, wp);
|
|
|
|
arb_mul(c, t, v, prec);
|
|
arb_mul(d, b, v, prec);
|
|
arb_neg(d, d);
|
|
|
|
arb_clear(r);
|
|
arb_clear(t);
|
|
arb_clear(u);
|
|
arb_clear(v);
|
|
|
|
#undef a
|
|
#undef b
|
|
#undef c
|
|
#undef d
|
|
}
|
|
|
|
static void
|
|
_acb_rsqrt(acb_t y, const acb_t x, slong prec)
|
|
{
|
|
if (acb_rel_accuracy_bits(x) > 10)
|
|
{
|
|
_acb_rsqrt1(y, x, prec);
|
|
}
|
|
else if (acb_contains_zero(x))
|
|
{
|
|
acb_indeterminate(y);
|
|
}
|
|
else
|
|
{
|
|
/* use derivative (todo: compute better bounds) */
|
|
mag_t t, u;
|
|
|
|
mag_init(t);
|
|
mag_init(u);
|
|
|
|
acb_get_mag_lower(t, x);
|
|
|
|
mag_rsqrt(u, t);
|
|
mag_div(u, u, t);
|
|
mag_hypot(t, arb_radref(acb_realref(x)), arb_radref(acb_imagref(x)));
|
|
mag_mul(u, u, t);
|
|
|
|
acb_set(y, x);
|
|
mag_zero(arb_radref(acb_realref(y)));
|
|
mag_zero(arb_radref(acb_imagref(y)));
|
|
|
|
_acb_rsqrt1(y, y, prec);
|
|
acb_add_error_mag(y, u);
|
|
|
|
mag_clear(t);
|
|
mag_clear(u);
|
|
}
|
|
}
|
|
|
|
void
|
|
acb_rsqrt(acb_t y, const acb_t x, slong prec)
|
|
{
|
|
#define a acb_realref(x)
|
|
#define b acb_imagref(x)
|
|
#define c acb_realref(y)
|
|
#define d acb_imagref(y)
|
|
|
|
if (arb_is_zero(b))
|
|
{
|
|
if (arb_is_nonnegative(a))
|
|
{
|
|
arb_rsqrt(c, a, prec);
|
|
arb_zero(d);
|
|
return;
|
|
}
|
|
else if (arb_is_nonpositive(a))
|
|
{
|
|
arb_neg(d, a);
|
|
arb_rsqrt(d, d, prec);
|
|
arb_neg(d, d);
|
|
arb_zero(c);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (arb_is_zero(a))
|
|
{
|
|
if (arb_is_nonnegative(b))
|
|
{
|
|
arb_mul_2exp_si(c, b, 1);
|
|
arb_rsqrt(c, c, prec);
|
|
arb_neg(d, c);
|
|
return;
|
|
}
|
|
else if (arb_is_nonpositive(b))
|
|
{
|
|
arb_mul_2exp_si(c, b, 1);
|
|
arb_neg(c, c);
|
|
arb_rsqrt(c, c, prec);
|
|
arb_set(d, c);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (arb_is_positive(a))
|
|
{
|
|
_acb_rsqrt(y, x, prec);
|
|
}
|
|
else if (arb_is_nonnegative(b))
|
|
{
|
|
acb_neg(y, x);
|
|
_acb_rsqrt(y, y, prec);
|
|
acb_div_onei(y, y);
|
|
}
|
|
else if (arb_is_negative(b))
|
|
{
|
|
acb_neg(y, x);
|
|
_acb_rsqrt(y, y, prec);
|
|
acb_mul_onei(y, y);
|
|
}
|
|
else
|
|
{
|
|
/* todo: more elegant solution? */
|
|
acb_t t;
|
|
acb_init(t);
|
|
acb_neg(y, x);
|
|
_acb_rsqrt(y, y, prec);
|
|
acb_mul_onei(t, y);
|
|
acb_div_onei(y, y);
|
|
acb_union(y, y, t, prec);
|
|
acb_clear(t);
|
|
}
|
|
|
|
#undef a
|
|
#undef b
|
|
#undef c
|
|
#undef d
|
|
}
|
|
|
|
void
|
|
acb_rsqrt_analytic(acb_ptr res, const acb_t z, int analytic, slong prec)
|
|
{
|
|
if (analytic && arb_contains_zero(acb_imagref(z)) &&
|
|
!arb_is_positive(acb_realref(z)))
|
|
{
|
|
acb_indeterminate(res);
|
|
}
|
|
else
|
|
{
|
|
acb_rsqrt(res, z, prec);
|
|
}
|
|
}
|
|
|