/*============================================================================= 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) 2013 Fredrik Johansson ******************************************************************************/ #include "gamma.h" #include "arith.h" void rising_difference_polynomial(fmpz * s, fmpz * c, ulong m); void gamma_rising_fmpcb_ui_delta(fmpcb_t y, const fmpcb_t x, ulong n, ulong m, long prec) { fmpcb_ptr xs; fmpcb_t t, u, v; ulong i, k, rem; fmpz_t c, h; fmpz *s, *d; long wp; if (n == 0) { fmpcb_one(y); return; } if (n == 1) { fmpcb_set_round(y, x, prec); return; } wp = FMPR_PREC_ADD(prec, FLINT_BIT_COUNT(n)); fmpcb_init(t); fmpcb_init(u); fmpcb_init(v); fmpz_init(c); fmpz_init(h); if (m == 0) { ulong m1, m2; m1 = 0.2 * pow(2.0 * wp, 0.4); m2 = n_sqrt(n); m = FLINT_MIN(m1, m2); } m = FLINT_MIN(m, n); m = FLINT_MAX(m, 1); xs = _fmpcb_vec_init(m + 1); d = _fmpz_vec_init(m * m); s = _fmpz_vec_init(m + 1); _fmpcb_vec_set_powers(xs, x, m + 1, wp); rising_difference_polynomial(s, d, m); /* tail */ rem = m; while (rem + m <= n) rem += m; fmpcb_one(y); for (k = rem; k < n; k++) { fmpcb_add_ui(t, xs + 1, k, wp); fmpcb_mul(y, y, t, wp); } /* initial rising factorial */ fmpcb_zero(t); for (i = 1; i <= m; i++) fmpcb_addmul_fmpz(t, xs + i, s + i, wp); fmpcb_mul(y, y, t, wp); /* the leading coefficient is always the same */ fmpcb_mul_fmpz(xs + m - 1, xs + m - 1, d + m - 1 + 0, wp); for (k = 0; k + 2 * m <= n; k += m) { for (i = 0; i < m - 1; i++) { fmpz_set_ui(h, k); _fmpz_poly_evaluate_horner_fmpz(c, d + i * m, m - i, h); if (i == 0) fmpcb_add_fmpz(t, t, c, wp); else fmpcb_addmul_fmpz(t, xs + i, c, wp); } fmpcb_add(t, t, xs + m - 1, wp); fmpcb_mul(y, y, t, wp); } fmpcb_set_round(y, y, prec); fmpcb_clear(t); fmpcb_clear(u); fmpcb_clear(v); _fmpcb_vec_clear(xs, m + 1); _fmpz_vec_clear(d, m * m); _fmpz_vec_clear(s, m + 1); fmpz_clear(c); fmpz_clear(h); }