| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,380 @@ | ||
| /*============================================================================= | ||
| 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) 2015 Fredrik Johansson | ||
| ******************************************************************************/ | ||
|
|
||
| #include "arb.h" | ||
| #include "arith.h" | ||
| #include "double_extras.h" | ||
|
|
||
| /* \sum_{k=0}^{a-1} \frac{k^n}{k!} */ | ||
| /* b = a * \frac{(a-1)^n}{(a-1)!} */ | ||
| /* assumes n > 0, a >= 0 */ | ||
| static void | ||
| lower_bound(mag_t bound, const fmpz_t a, const fmpz_t n) | ||
| { | ||
| arb_t t, u; | ||
| long wp; | ||
|
|
||
| if (fmpz_is_zero(a)) | ||
| { | ||
| mag_zero(bound); | ||
| return; | ||
| } | ||
|
|
||
| wp = 10 + fmpz_bits(n); | ||
|
|
||
| arb_init(t); | ||
| arb_init(u); | ||
|
|
||
| /* decreasing condition: a * (a-1)^n < a^n */ | ||
| arb_set_fmpz(t, a); | ||
| arb_pow_fmpz(t, t, n, wp); | ||
|
|
||
| arb_set_fmpz(u, a); | ||
| arb_sub_ui(u, u, 1, wp); | ||
| arb_pow_fmpz(u, u, n, wp); | ||
| arb_mul_fmpz(u, u, a, wp); | ||
|
|
||
| if (arb_lt(u, t)) | ||
| { | ||
| arb_gamma_fmpz(t, a, wp); | ||
| arb_div(t, u, t, wp); | ||
| arb_get_mag(bound, t); | ||
| } | ||
| else | ||
| { | ||
| mag_inf(bound); | ||
| } | ||
|
|
||
| arb_clear(t); | ||
| arb_clear(u); | ||
| } | ||
|
|
||
| /* | ||
| b^n [ ((b+1)/b)^n ((b+2)/b)^n ] | ||
| --- [ 1 + ----------- + ----------- + .... ] | ||
| b! [ (b+1) (b+1)(b+2) ] | ||
| */ | ||
| static void | ||
| upper_bound(mag_t bound, const fmpz_t b, const fmpz_t n) | ||
| { | ||
| arb_t t, u; | ||
| long wp; | ||
|
|
||
| wp = 10 + 2 * fmpz_bits(n); | ||
|
|
||
| arb_init(t); | ||
| arb_init(u); | ||
|
|
||
| /* decreasing condition: (1+1/b)^n / (b+1) < 1 */ | ||
| /* geometric series factor: 1 + t^2 + t^3 + ... = 1/(1-t) */ | ||
| arb_one(t); | ||
| arb_div_fmpz(t, t, b, wp); | ||
| arb_add_ui(t, t, 1, wp); | ||
| arb_pow_fmpz(t, t, n, wp); | ||
| arb_set_fmpz(u, b); | ||
| arb_add_ui(u, u, 1, wp); | ||
| arb_div(t, t, u, wp); | ||
|
|
||
| arb_one(u); | ||
| arb_sub(u, u, t, wp); | ||
|
|
||
| if (arb_is_positive(u)) | ||
| { | ||
| arb_set_fmpz(t, b); | ||
| arb_pow_fmpz(t, t, n, wp); | ||
| arb_div(t, t, u, wp); | ||
|
|
||
| arb_set_fmpz(u, b); | ||
| arb_add_ui(u, u, 1, wp); | ||
| arb_gamma(u, u, wp); | ||
|
|
||
| arb_div(t, t, u, wp); | ||
| arb_get_mag(bound, t); | ||
| } | ||
| else | ||
| { | ||
| mag_inf(bound); | ||
| } | ||
|
|
||
| arb_clear(t); | ||
| arb_clear(u); | ||
| } | ||
|
|
||
| /* approximate; need not give a correct bound, but | ||
| should be accurate so that we find near-optimal cutoffs | ||
| (we compute correct bounds elsewhere) */ | ||
| static void | ||
| _arb_bell_mag(fmpz_t mmag, const fmpz_t n, const fmpz_t k) | ||
| { | ||
| if (fmpz_cmp_ui(k, 1) <= 0) | ||
| { | ||
| fmpz_set(mmag, k); | ||
| } | ||
| else if (fmpz_bits(n) < 50) | ||
| { | ||
| double dn, dk, z, u, lg; | ||
|
|
||
| dn = fmpz_get_d(n); | ||
| dk = fmpz_get_d(k); | ||
|
|
||
| z = dk + 1.0; | ||
| u = 1.0 / z; | ||
| lg = 0.91893853320467274178 + (z-0.5)*log(z) - z; | ||
| lg = lg + u * (0.08333333333333333 - 0.00277777777777777778 * (u * u) | ||
| + 0.00079365079365079365079 * ((u * u) * (u * u))); | ||
| u = (dn * log(dk) - lg) * 1.4426950408889634074 + 1.0; | ||
| fmpz_set_d(mmag, u); | ||
| } | ||
| else | ||
| { | ||
| arb_t t, u; | ||
| arf_t bound; | ||
| long prec; | ||
|
|
||
| arb_init(t); | ||
| arb_init(u); | ||
| arf_init(bound); | ||
|
|
||
| prec = 10 + 1.1 * fmpz_bits(n); | ||
|
|
||
| arb_log_fmpz(t, k, prec); | ||
| arb_mul_fmpz(t, t, n, prec); | ||
|
|
||
| arb_set_fmpz(u, k); | ||
| arb_add_ui(u, u, 1, prec); | ||
| arb_lgamma(u, u, prec); | ||
|
|
||
| arb_sub(t, t, u, prec); | ||
|
|
||
| arb_const_log2(u, prec); | ||
| arb_div(t, t, u, prec); | ||
|
|
||
| arf_set_mag(bound, arb_radref(t)); | ||
| arf_add(bound, arb_midref(t), bound, prec, ARF_RND_CEIL); | ||
| arf_get_fmpz(mmag, bound, ARF_RND_CEIL); | ||
|
|
||
| arb_clear(t); | ||
| arb_clear(u); | ||
| arf_clear(bound); | ||
| } | ||
| } | ||
|
|
||
| void | ||
| arb_bell_find_cutoffs(fmpz_t A, fmpz_t B, fmpz_t M, fmpz_t Mmag, const fmpz_t n, long prec) | ||
| { | ||
| fmpz_t a, amag, b, bmag, m, mmag, w, wmag, Amag, Bmag; | ||
|
|
||
| fmpz_init(a); fmpz_init(amag); | ||
| fmpz_init(b); fmpz_init(bmag); | ||
| fmpz_init(m); fmpz_init(mmag); | ||
| fmpz_init(w); fmpz_init(wmag); | ||
| fmpz_init(Amag); fmpz_init(Bmag); | ||
|
|
||
| if (fmpz_bits(n) < 53 && 0) | ||
| { | ||
| double dn = fmpz_get_d(n); | ||
|
|
||
| fmpz_set_d(M, dn / d_lambertw(dn)); | ||
| _arb_bell_mag(Mmag, n, M); | ||
| } | ||
| else | ||
| { | ||
| /* do ternary search for M */ | ||
| fmpz_zero(a); | ||
| fmpz_mul_ui(b, n, 2); | ||
| fmpz_zero(amag); | ||
| fmpz_zero(bmag); | ||
|
|
||
| while (_fmpz_sub_small(b, a) > 4) | ||
| { | ||
| fmpz_sub(m, b, a); | ||
| fmpz_tdiv_q_ui(m, m, 3); | ||
| fmpz_mul_2exp(w, m, 1); | ||
| fmpz_add(m, a, m); | ||
| fmpz_add(w, a, w); | ||
|
|
||
| _arb_bell_mag(mmag, n, m); | ||
| _arb_bell_mag(wmag, n, w); | ||
|
|
||
| if (fmpz_cmp(mmag, wmag) < 0) | ||
| { | ||
| fmpz_swap(a, m); | ||
| fmpz_swap(amag, mmag); | ||
| } | ||
| else | ||
| { | ||
| fmpz_swap(b, w); | ||
| fmpz_swap(bmag, wmag); | ||
| } | ||
| } | ||
|
|
||
| fmpz_set(M, a); | ||
| fmpz_set(Mmag, amag); | ||
| } | ||
|
|
||
| /* bisect for A */ | ||
| fmpz_zero(a); | ||
| fmpz_zero(amag); | ||
| fmpz_set(b, M); | ||
| fmpz_set(bmag, Mmag); | ||
|
|
||
| while (_fmpz_sub_small(b, a) > 4) | ||
| { | ||
| fmpz_sub(m, b, a); | ||
| fmpz_tdiv_q_2exp(m, m, 1); | ||
| fmpz_add(m, a, m); | ||
|
|
||
| _arb_bell_mag(mmag, n, m); | ||
|
|
||
| /* mmag < Mmag - p */ | ||
| if (_fmpz_sub_small(mmag, Mmag) < -prec) | ||
| { | ||
| fmpz_swap(a, m); | ||
| fmpz_swap(amag, mmag); | ||
| } | ||
| else | ||
| { | ||
| fmpz_swap(b, m); | ||
| fmpz_swap(bmag, mmag); | ||
| } | ||
| } | ||
|
|
||
| fmpz_set(A, a); | ||
| fmpz_set(Amag, amag); | ||
|
|
||
| /* bisect for B */ | ||
| fmpz_set(a, M); | ||
| fmpz_set(amag, Mmag); | ||
| fmpz_mul_ui(b, n, 2); | ||
| fmpz_zero(bmag); | ||
|
|
||
| while (_fmpz_sub_small(b, a) > 4) | ||
| { | ||
| fmpz_sub(m, b, a); | ||
| fmpz_tdiv_q_2exp(m, m, 1); | ||
| fmpz_add(m, a, m); | ||
|
|
||
| _arb_bell_mag(mmag, n, m); | ||
|
|
||
| /* mmag < Mmag - p */ | ||
| if (_fmpz_sub_small(mmag, Mmag) < -prec || fmpz_sgn(mmag) <= 0) | ||
| { | ||
| fmpz_swap(b, m); | ||
| fmpz_swap(bmag, mmag); | ||
| } | ||
| else | ||
| { | ||
| fmpz_swap(a, m); | ||
| fmpz_swap(amag, mmag); | ||
| } | ||
| } | ||
|
|
||
| fmpz_set(B, a); | ||
| fmpz_set(Bmag, amag); | ||
|
|
||
| fmpz_clear(a); fmpz_clear(amag); | ||
| fmpz_clear(b); fmpz_clear(bmag); | ||
| fmpz_clear(m); fmpz_clear(mmag); | ||
| fmpz_clear(w); fmpz_clear(wmag); | ||
| fmpz_clear(Amag); fmpz_clear(Bmag); | ||
| } | ||
|
|
||
| void | ||
| arb_bell_fmpz(arb_t res, const fmpz_t n, long prec) | ||
| { | ||
| fmpz_t a, b, m, mmag, c; | ||
| arb_t t; | ||
| mag_t bound; | ||
|
|
||
| if (fmpz_sgn(n) < 0) | ||
| { | ||
| arb_zero(res); | ||
| return; | ||
| } | ||
|
|
||
| if (fmpz_fits_si(n)) | ||
| { | ||
| long nn = fmpz_get_si(n); | ||
|
|
||
| /* compute exactly if we would be computing at least half the bits | ||
| of the exact number */ | ||
| if (nn < 50 || prec > 0.5 * nn * log(0.7*nn / log(nn)) * 1.442695041) | ||
| { | ||
| fmpz_init(a); | ||
| arith_bell_number(a, nn); | ||
| arb_set_round_fmpz(res, a, prec); | ||
| fmpz_clear(a); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| fmpz_init(a); | ||
| fmpz_init(b); | ||
| fmpz_init(m); | ||
| fmpz_init(mmag); | ||
| fmpz_init(c); | ||
| arb_init(t); | ||
| mag_init(bound); | ||
|
|
||
| arb_bell_find_cutoffs(a, b, m, mmag, n, 1.03 * prec + fmpz_bits(n) + 2); | ||
|
|
||
| /* cutoff: n > 2^12 * prec^2 */ | ||
| fmpz_set_ui(c, prec); | ||
| fmpz_mul_ui(c, c, prec); | ||
| fmpz_mul_2exp(c, c, 12); | ||
|
|
||
| if (fmpz_cmp(n, c) > 0) | ||
| arb_bell_sum_taylor(res, n, a, b, mmag, prec + 2); | ||
| else | ||
| arb_bell_sum_bsplit(res, n, a, b, mmag, prec + 2); | ||
|
|
||
| lower_bound(bound, a, n); | ||
| arb_add_error_mag(res, bound); | ||
|
|
||
| upper_bound(bound, b, n); | ||
| arb_add_error_mag(res, bound); | ||
|
|
||
| arb_const_e(t, prec + 2); | ||
| arb_div(res, res, t, prec); | ||
|
|
||
| fmpz_clear(a); | ||
| fmpz_clear(b); | ||
| fmpz_clear(m); | ||
| fmpz_clear(mmag); | ||
| fmpz_clear(c); | ||
| arb_clear(t); | ||
| mag_clear(bound); | ||
| } | ||
|
|
||
| void | ||
| arb_bell_ui(arb_t res, ulong n, long prec) | ||
| { | ||
| fmpz_t t; | ||
| fmpz_init(t); | ||
| fmpz_set_ui(t, n); | ||
| arb_bell_fmpz(res, t, prec); | ||
| fmpz_clear(t); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| /*============================================================================= | ||
| 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) 2015 Fredrik Johansson | ||
| ******************************************************************************/ | ||
|
|
||
| #include "arb.h" | ||
|
|
||
| static void | ||
| bsplit(arb_t P, arb_t Q, const fmpz_t n, const fmpz_t a, const fmpz_t b, long prec) | ||
| { | ||
| fmpz_t t; | ||
| fmpz_init(t); | ||
| fmpz_sub(t, b, a); | ||
|
|
||
| if (fmpz_sgn(t) <= 0) | ||
| { | ||
| arb_zero(P); | ||
| arb_one(Q); | ||
| } | ||
| else if (fmpz_cmp_ui(t, 20) < 0) | ||
| { | ||
| long steps, k; | ||
| arb_t u; | ||
| arb_init(u); | ||
|
|
||
| arb_zero(P); | ||
| arb_one(Q); | ||
|
|
||
| steps = fmpz_get_si(t); | ||
|
|
||
| for (k = steps - 1; k >= 0; k--) | ||
| { | ||
| fmpz_add_ui(t, a, k); | ||
|
|
||
| arb_set_round_fmpz(u, t, prec); | ||
| arb_pow_fmpz(u, u, n, prec); | ||
| arb_addmul(P, Q, u, prec); | ||
|
|
||
| if (!fmpz_is_zero(t)) | ||
| arb_mul_fmpz(Q, Q, t, prec); | ||
| } | ||
|
|
||
| arb_clear(u); | ||
| } | ||
| else | ||
| { | ||
| fmpz_t m; | ||
| arb_t P1, Q2; | ||
|
|
||
| fmpz_init(m); | ||
| arb_init(P1); | ||
| arb_init(Q2); | ||
|
|
||
| fmpz_add(m, a, b); | ||
| fmpz_tdiv_q_2exp(m, m, 1); | ||
|
|
||
| bsplit(P1, Q, n, a, m, prec); | ||
| bsplit(P, Q2, n, m, b, prec); | ||
|
|
||
| arb_mul(Q, Q, Q2, prec); | ||
| arb_addmul(P, P1, Q2, prec); | ||
|
|
||
| fmpz_clear(m); | ||
| arb_clear(P1); | ||
| arb_clear(Q2); | ||
| } | ||
|
|
||
| fmpz_clear(t); | ||
| } | ||
|
|
||
| void | ||
| arb_bell_sum_bsplit(arb_t res, const fmpz_t n, | ||
| const fmpz_t a, const fmpz_t b, const fmpz_t mmag, long prec) | ||
| { | ||
| if (fmpz_cmp(a, b) >= 0) | ||
| { | ||
| arb_zero(res); | ||
| } | ||
| else | ||
| { | ||
| long wp; | ||
| arb_t P, Q; | ||
|
|
||
| wp = _fmpz_sub_small(b, a); | ||
| wp = FLINT_BIT_COUNT(FLINT_ABS(wp)); | ||
| wp = prec + fmpz_bits(n) + fmpz_bits(a) + wp; | ||
|
|
||
| arb_init(P); | ||
| arb_init(Q); | ||
|
|
||
| bsplit(P, Q, n, a, b, wp); | ||
| arb_div(res, P, Q, wp); | ||
|
|
||
| if (!fmpz_is_zero(a)) | ||
| { | ||
| arb_gamma_fmpz(P, a, wp); | ||
| arb_div(res, res, P, wp); | ||
| } | ||
|
|
||
| arb_set_round(res, res, prec); | ||
|
|
||
| arb_clear(P); | ||
| arb_clear(Q); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| /*============================================================================= | ||
| 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) 2015 Fredrik Johansson | ||
| ******************************************************************************/ | ||
|
|
||
| #include "arb.h" | ||
| #include "arb_poly.h" | ||
|
|
||
| /* tuning parameter */ | ||
| #define RADIUS_BITS 3 | ||
|
|
||
| void | ||
| _arb_bell_sum_taylor(arb_t res, const fmpz_t n, | ||
| const fmpz_t a, const fmpz_t b, const fmpz_t mmag, long tol) | ||
| { | ||
| fmpz_t m, r, R, tmp; | ||
| mag_t B, C, D, bound; | ||
| arb_t t, u; | ||
| long wp, k, N; | ||
|
|
||
| if (_fmpz_sub_small(b, a) < 5) | ||
| { | ||
| arb_bell_sum_bsplit(res, n, a, b, mmag, tol); | ||
| return; | ||
| } | ||
|
|
||
| fmpz_init(m); | ||
| fmpz_init(r); | ||
| fmpz_init(R); | ||
| fmpz_init(tmp); | ||
|
|
||
| /* r = max(m - a, b - m) */ | ||
| /* m = a + (b - a) / 2 */ | ||
| fmpz_sub(r, b, a); | ||
| fmpz_cdiv_q_2exp(r, r, 1); | ||
| fmpz_add(m, a, r); | ||
|
|
||
| fmpz_mul_2exp(R, r, RADIUS_BITS); | ||
|
|
||
| mag_init(B); | ||
| mag_init(C); | ||
| mag_init(D); | ||
| mag_init(bound); | ||
|
|
||
| arb_init(t); | ||
| arb_init(u); | ||
|
|
||
| if (fmpz_cmp(R, m) >= 0) | ||
| { | ||
| mag_inf(C); | ||
| mag_inf(D); | ||
| } | ||
| else | ||
| { | ||
| /* C = exp(R * |F'(m)| + (1/2) R^2 * (n/(m-R)^2 + 1/(m-R))) */ | ||
| /* C = exp(R * (|F'(m)| + (1/2) R * (n/(m-R) + 1)/(m-R))) */ | ||
| /* D = (1/2) R * (n/(m-R) + 1)/(m-R) */ | ||
| fmpz_sub(tmp, m, R); | ||
| mag_set_fmpz(D, n); | ||
| mag_div_fmpz(D, D, tmp); | ||
| mag_one(C); | ||
| mag_add(D, D, C); | ||
| mag_div_fmpz(D, D, tmp); | ||
| mag_mul_fmpz(D, D, R); | ||
| mag_mul_2exp_si(D, D, -1); | ||
|
|
||
| /* C = |F'(m)| */ | ||
| wp = 20 + 1.05 * fmpz_bits(n); | ||
| arb_set_fmpz(t, n); | ||
| arb_div_fmpz(t, t, m, wp); | ||
| fmpz_add_ui(tmp, m, 1); | ||
| arb_set_fmpz(u, tmp); | ||
| arb_digamma(u, u, wp); | ||
| arb_sub(t, t, u, wp); | ||
| arb_get_mag(C, t); | ||
|
|
||
| /* C = exp(R * (C + D)) */ | ||
| mag_add(C, C, D); | ||
| mag_mul_fmpz(C, C, R); | ||
| mag_exp(C, C); | ||
| } | ||
|
|
||
| if (mag_cmp_2exp_si(C, tol / 4 + 2) > 0) | ||
| { | ||
| _arb_bell_sum_taylor(res, n, a, m, mmag, tol); | ||
| _arb_bell_sum_taylor(t, n, m, b, mmag, tol); | ||
| arb_add(res, res, t, 2 * tol); | ||
| } | ||
| else | ||
| { | ||
| arb_ptr mx, ser1, ser2, ser3; | ||
|
|
||
| /* D = T(m) */ | ||
| wp = 20 + 1.05 * fmpz_bits(n); | ||
| arb_set_fmpz(t, m); | ||
| arb_pow_fmpz(t, t, n, wp); | ||
| fmpz_add_ui(tmp, m, 1); | ||
| arb_gamma_fmpz(u, tmp, wp); | ||
| arb_div(t, t, u, wp); | ||
| arb_get_mag(D, t); | ||
|
|
||
| /* error bound: (b-a) * C * D * B^N / (1 - B), B = r/R */ | ||
| /* ((b-a) * C * D * 2) * 2^(-N*RADIUS_BITS) */ | ||
|
|
||
| /* ((b-a) * C * D * 2) */ | ||
| mag_mul(bound, C, D); | ||
| mag_mul_2exp_si(bound, bound, 1); | ||
| fmpz_sub(tmp, b, a); | ||
| mag_mul_fmpz(bound, bound, tmp); | ||
|
|
||
| /* N = (tol + log2((b-a)*C*D*2) - mmag) / RADIUS_BITS */ | ||
| if (mmag == NULL) | ||
| { | ||
| /* estimate D ~= 2^mmag */ | ||
| fmpz_add_ui(tmp, MAG_EXPREF(C), tol); | ||
| fmpz_cdiv_q_ui(tmp, tmp, RADIUS_BITS); | ||
| } | ||
| else | ||
| { | ||
| fmpz_sub(tmp, MAG_EXPREF(bound), mmag); | ||
| fmpz_add_ui(tmp, tmp, tol); | ||
| fmpz_cdiv_q_ui(tmp, tmp, RADIUS_BITS); | ||
| } | ||
|
|
||
| if (fmpz_cmp_ui(tmp, 5 * tol / 4) > 0) | ||
| N = 5 * tol / 4; | ||
| else if (fmpz_cmp_ui(tmp, 2) < 0) | ||
| N = 2; | ||
| else | ||
| N = fmpz_get_ui(tmp); | ||
|
|
||
| /* multiply by 2^(-N*RADIUS_BITS) */ | ||
| mag_mul_2exp_si(bound, bound, -N * RADIUS_BITS); | ||
|
|
||
| mx = _arb_vec_init(2); | ||
| ser1 = _arb_vec_init(N); | ||
| ser2 = _arb_vec_init(N); | ||
| ser3 = _arb_vec_init(N); | ||
|
|
||
| /* estimate (this should work for moderate n and tol) */ | ||
| wp = 1.1 * tol + 1.05 * fmpz_bits(n) + 5; | ||
|
|
||
| /* increase precision until convergence */ | ||
| while (1) | ||
| { | ||
| /* (m+x)^n / gamma(m+1+x) */ | ||
| arb_set_fmpz(mx, m); | ||
| arb_one(mx + 1); | ||
| _arb_poly_log_series(ser1, mx, 2, N, wp); | ||
| for (k = 0; k < N; k++) | ||
| arb_mul_fmpz(ser1 + k, ser1 + k, n, wp); | ||
| arb_add_ui(mx, mx, 1, wp); | ||
| _arb_poly_lgamma_series(ser2, mx, 2, N, wp); | ||
| _arb_vec_sub(ser1, ser1, ser2, N, wp); | ||
| _arb_poly_exp_series(ser3, ser1, N, N, wp); | ||
|
|
||
| /* t = a - m, u = b - m */ | ||
| arb_set_fmpz(t, a); | ||
| arb_sub_fmpz(t, t, m, wp); | ||
| arb_set_fmpz(u, b); | ||
| arb_sub_fmpz(u, u, m, wp); | ||
| arb_power_sum_vec(ser1, t, u, N, wp); | ||
|
|
||
| arb_zero(res); | ||
| for (k = 0; k < N; k++) | ||
| arb_addmul(res, ser3 + k, ser1 + k, wp); | ||
|
|
||
| if (mmag != NULL) | ||
| { | ||
| if (_fmpz_sub_small(MAG_EXPREF(arb_radref(res)), mmag) <= -tol) | ||
| break; | ||
| } | ||
| else | ||
| { | ||
| if (arb_rel_accuracy_bits(res) >= tol) | ||
| break; | ||
| } | ||
|
|
||
| wp = 2 * wp; | ||
| } | ||
|
|
||
| /* add the series truncation bound */ | ||
| arb_add_error_mag(res, bound); | ||
|
|
||
| _arb_vec_clear(mx, 2); | ||
| _arb_vec_clear(ser1, N); | ||
| _arb_vec_clear(ser2, N); | ||
| _arb_vec_clear(ser3, N); | ||
| } | ||
|
|
||
| mag_clear(B); | ||
| mag_clear(C); | ||
| mag_clear(D); | ||
| mag_clear(bound); | ||
| arb_clear(t); | ||
| arb_clear(u); | ||
|
|
||
| fmpz_clear(m); | ||
| fmpz_clear(r); | ||
| fmpz_clear(R); | ||
| fmpz_clear(tmp); | ||
| } | ||
|
|
||
| void | ||
| arb_bell_sum_taylor(arb_t res, const fmpz_t n, | ||
| const fmpz_t a, const fmpz_t b, const fmpz_t mmag, long prec) | ||
| { | ||
| _arb_bell_sum_taylor(res, n, a, b, mmag, prec + 5); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| /*============================================================================= | ||
| 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) 2015 Fredrik Johansson | ||
| ******************************************************************************/ | ||
|
|
||
| #include <stdio.h> | ||
| #include "arb.h" | ||
|
|
||
| int main() | ||
| { | ||
| long iter; | ||
| flint_rand_t state; | ||
|
|
||
| printf("bell_fmpz...."); | ||
| fflush(stdout); | ||
|
|
||
| flint_randinit(state); | ||
|
|
||
| for (iter = 0; iter < 5000; iter++) | ||
| { | ||
| arb_t b1, b2; | ||
| fmpz_t n; | ||
| long prec1, prec2, acc1, acc2; | ||
|
|
||
| fmpz_init(n); | ||
| arb_init(b1); | ||
| arb_init(b2); | ||
|
|
||
| if (iter % 100 == 0) | ||
| { | ||
| fmpz_randtest(n, state, 1 + n_randint(state, 100)); | ||
| fmpz_abs(n, n); | ||
| prec1 = 2 + n_randint(state, 200); | ||
| prec2 = 2 + n_randint(state, 200); | ||
| } | ||
| else | ||
| { | ||
| fmpz_randtest(n, state, 1 + n_randint(state, 20)); | ||
| fmpz_abs(n, n); | ||
| prec1 = 2 + n_randint(state, 1000); | ||
| prec2 = 2 + n_randint(state, 1000); | ||
| } | ||
|
|
||
| arb_bell_fmpz(b1, n, prec1); | ||
| arb_bell_fmpz(b2, n, prec2); | ||
|
|
||
| if (!arb_overlaps(b1, b2)) | ||
| { | ||
| printf("FAIL: overlap\n\n"); | ||
| printf("n = "); fmpz_print(n); printf("\n\n"); | ||
| printf("b1 = "); arb_printn(b1, 50, 0); printf("\n\n"); | ||
| printf("b2 = "); arb_printn(b2, 50, 0); printf("\n\n"); | ||
| abort(); | ||
| } | ||
|
|
||
| acc1 = arb_rel_accuracy_bits(b1); | ||
| acc2 = arb_rel_accuracy_bits(b2); | ||
|
|
||
| if (acc1 < prec1 - 4 || acc2 < prec2 - 4) | ||
| { | ||
| printf("FAIL: poor accuracy\n\n"); | ||
| printf("prec1 = %ld, acc1 = %ld\n", prec1, acc1); | ||
| printf("prec2 = %ld, acc2 = %ld\n", prec2, acc2); | ||
| printf("n = "); fmpz_print(n); printf("\n\n"); | ||
| printf("b1 = "); arb_printn(b1, 50, 0); printf("\n\n"); | ||
| printf("b2 = "); arb_printn(b2, 50, 0); printf("\n\n"); | ||
| abort(); | ||
| } | ||
|
|
||
| arb_clear(b1); | ||
| arb_clear(b2); | ||
| fmpz_clear(n); | ||
| } | ||
|
|
||
| flint_randclear(state); | ||
| flint_cleanup(); | ||
| printf("PASS\n"); | ||
| return EXIT_SUCCESS; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /*============================================================================= | ||
| 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) 2015 Fredrik Johansson | ||
| ******************************************************************************/ | ||
|
|
||
| #include <stdio.h> | ||
| #include "arb.h" | ||
|
|
||
| int main() | ||
| { | ||
| long iter; | ||
| flint_rand_t state; | ||
|
|
||
| printf("bell_sum_taylor...."); | ||
| fflush(stdout); | ||
|
|
||
| flint_randinit(state); | ||
|
|
||
| for (iter = 0; iter < 1000; iter++) | ||
| { | ||
| arb_t s1, s2; | ||
| fmpz_t a, b, n; | ||
| long prec; | ||
|
|
||
| arb_init(s1); | ||
| arb_init(s2); | ||
| fmpz_init(a); | ||
| fmpz_init(b); | ||
| fmpz_init(n); | ||
|
|
||
| prec = 2 + n_randint(state, 300); | ||
| fmpz_randtest_unsigned(n, state, 1 + n_randint(state, 100)); | ||
| fmpz_randtest_unsigned(a, state, 1 + n_randint(state, 100)); | ||
| fmpz_add_ui(b, a, n_randint(state, 100)); | ||
|
|
||
| arb_bell_sum_bsplit(s1, n, a, b, NULL, prec); | ||
| arb_bell_sum_taylor(s2, n, a, b, NULL, prec); | ||
|
|
||
| if (!arb_overlaps(s1, s2) || (arb_rel_accuracy_bits(s1) < prec - 4) | ||
| || (arb_rel_accuracy_bits(s2) < prec - 4)) | ||
| { | ||
| printf("FAIL: overlap or accuracy\n\n"); | ||
| printf("prec = %ld\n\n", prec); | ||
| printf("n = "); fmpz_print(n); printf("\n\n"); | ||
| printf("a = "); fmpz_print(a); printf("\n\n"); | ||
| printf("b = "); fmpz_print(b); printf("\n\n"); | ||
| printf("s1 = "); arb_printn(s1, 100, 0); printf("\n\n"); | ||
| printf("s2 = "); arb_printn(s2, 100, 0); printf("\n\n"); | ||
| abort(); | ||
| } | ||
|
|
||
| arb_clear(s1); | ||
| arb_clear(s2); | ||
| fmpz_clear(a); | ||
| fmpz_clear(b); | ||
| fmpz_clear(n); | ||
| } | ||
|
|
||
| flint_randclear(state); | ||
| flint_cleanup(); | ||
| printf("PASS\n"); | ||
| return EXIT_SUCCESS; | ||
| } | ||
|
|