arb/acb_hypgeom/pfq_choose_n.c

141 lines
3.6 KiB
C
Raw Normal View History

2014-11-08 13:49:15 +01:00
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2014 Fredrik Johansson
******************************************************************************/
#include "acb_hypgeom.h"
double mag_get_log2_d_approx(const mag_t x);
long
acb_hypgeom_pfq_choose_n(acb_srcptr a, long p,
acb_srcptr b, long q, const acb_t z, long prec)
{
long k, n, minimum_n, maximum_n;
mag_t zmag;
/* todo: first test for z = 0 and nonpositive integers */
double t, u;
double log2_z;
double log2_term;
double log2_factor;
double log2_term_max;
double * are;
double * aim;
double * bre;
double * bim;
mag_init(zmag);
are = flint_malloc(sizeof(double) * 2 * (p + q));
aim = are + p;
bre = aim + p;
bim = bre + q;
acb_get_mag(zmag, z);
log2_z = mag_get_log2_d_approx(zmag);
for (k = 0; k < p; k++)
{
are[k] = arf_get_d(arb_midref(acb_realref(a + k)), ARF_RND_DOWN);
aim[k] = arf_get_d(arb_midref(acb_imagref(a + k)), ARF_RND_DOWN);
}
minimum_n = 1;
maximum_n = 50 + 2 * prec;
for (k = 0; k < q; k++)
{
bre[k] = arf_get_d(arb_midref(acb_realref(b + k)), ARF_RND_DOWN);
bim[k] = arf_get_d(arb_midref(acb_imagref(b + k)), ARF_RND_DOWN);
if (bre[k] <= 0.25)
{
minimum_n = FLINT_MAX(minimum_n, 2 - bre[k]);
}
}
n = 1;
log2_term = 0.0;
log2_term_max = log2_term;
while (n <= maximum_n && minimum_n < maximum_n)
{
if (log2_term < log2_term_max - prec - 4 && n >= minimum_n)
break;
t = 1.0;
for (k = 0; k < FLINT_MAX(p, q); k++)
{
if (k < p)
{
u = (are[k] + n) * (are[k] + n) + (aim[k] * aim[k]);
u = FLINT_ABS(u);
if (u < 1e-8 || u > 1e100 || t > 1e100)
{
n++;
2014-11-08 13:49:15 +01:00
goto somethingstrange;
}
2014-11-08 13:49:15 +01:00
t *= u;
}
if (k < q)
{
u = (bre[k] + n) * (bre[k] + n) + (bim[k] * bim[k]);
u = FLINT_ABS(u);
if (u < 1e-8 || u > 1e100 || t > 1e100)
{
n++;
2014-11-08 13:49:15 +01:00
goto somethingstrange;
}
2014-11-08 13:49:15 +01:00
t /= u;
}
}
log2_factor = 0.5 * log(t) * 1.4426950408889634074 + log2_z;
/* For asymptotic series, require rapid decay */
if (p > q && n >= minimum_n && log2_factor > -0.2)
break;
log2_term += log2_factor;
log2_term_max = FLINT_MAX(log2_term_max, log2_term);
n++;
}
somethingstrange:
flint_free(are);
mag_clear(zmag);
return n;
}