void _padic_log_balanced(fmpz_t z, const fmpz_t y, long v, const fmpz_t p, long N) { fmpz_t pv, pN, r, t, u; long val; padic_inv_t S; fmpz_init(pv); fmpz_init(pN); fmpz_init(r); fmpz_init(t); fmpz_init(u); _padic_inv_precompute(S, p, N); fmpz_set(t, y); fmpz_set(pv, p); fmpz_pow_ui(pN, p, N); fmpz_zero(z); val = 1; /* TODO: Abort earlier if larger than $p^N$, possible with variable precision? */ while (!fmpz_is_zero(t)) { fmpz_mul(pv, pv, pv); fmpz_fdiv_qr(t, r, t, pv); if (!fmpz_is_zero(t)) { fmpz_mul(t, t, pv); fmpz_add_ui(u, r, 1); _padic_inv_precomp(u, u, S); fmpz_mul(t, t, u); fmpz_mod(t, t, pN); } if (!fmpz_is_zero(r)) { fmpz_neg(r, r); _padic_log_bsplit(r, r, val, p, N); fmpz_sub(z, z, r); } val *= 2; } fmpz_clear(pv); fmpz_clear(pN); fmpz_clear(r); fmpz_clear(t); fmpz_clear(u); _padic_inv_clear(S); }
static void precompute_nu(fmpz *nu, long *v, long M, const long *C, long lenC, long p, long N) { const long R = M / p; const long N2 = N + (M / (p - 1)); fmpz_t P, PN2, t; padic_inv_t S; double pinv; long i, j; fmpz_init_set_ui(P, p); fmpz_init(PN2); fmpz_pow_ui(PN2, P, N2); fmpz_init(t); /* Step 1. Compute $i! mod p^{N_2}$ where $N_2 \geq N + \max \ord_p (i!)$ Step 2. Invert the unit part of $i!$ modulo $p^N$ */ fmpz_one(nu + 0); for (i = 1; i <= R; i++) { fmpz_mul_ui(nu + i, nu + (i - 1), i); fmpz_mod(nu + i, nu + i, PN2); } /* Let j denote the greatest index s.t. nu[j] has been computed */ for (j = R, i = R + 1; i <= M; i++) { if (_bsearch(C, 0, lenC, i % p) != -1) { fmpz_mod_rfac_uiui(t, j + 1, i - j, PN2); fmpz_mul(nu + i, nu + j, t); fmpz_mod(nu + i, nu + i, PN2); j = i; } } _padic_inv_precompute(S, P, N); pinv = n_precompute_inverse(p); v[0] = 0; for (i = 1; i <= R; i++) { v[i] = - _fmpz_remove(nu + i, P, pinv); _padic_inv_precomp(nu + i, nu + i, S); } for (i = R + 1; i <= M; i++) { if (_bsearch(C, 0, lenC, i % p) != -1) { v[i] = - _fmpz_remove(nu + i, P, pinv); _padic_inv_precomp(nu + i, nu + i, S); } } fmpz_clear(P); fmpz_clear(PN2); fmpz_clear(t); _padic_inv_clear(S); }