/* p-adic logarithm */ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) { /* Compute the p-adic logarithm of a, which is supposed to be congruent to 1 mod p Algorithm: 1. we raise a at the power p^(v-1) (for a suitable v) in order to make it closer to 1 2. we write the new a as a product 1/a = (1 - a_0*p^v) (1 - a_1*p^(2*v) (1 - a_2*p^(4*v) ... with 0 <= a_i < p^(v*2^i). 3. we compute each log(1 - a_i*p^(v*2^i)) using Taylor expansion and a binary spliting strategy. */ unsigned long i, v, e, N, saveN, Np, tmp, trunc, step; double den = log(p); mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, mpz_tmp2, d, inv, mod2; mpz_t *num, *denom; mpz_init(mpz_tmp); mpz_init(mpz_tmp2); mpz_init(arg); mpz_set_ui(ans, 0); mpz_fdiv_r_ui(mpz_tmp, a, p); mpz_set(arg, a); /* First we make the argument closer to 1 by raising it to the p^(v-1) */ if (prec < p) { v = 0; e = 1; } else { v = (unsigned long)(log(prec)/den); // v here is v-1 e = pow(p,v); mpz_mul_ui(mpz_tmp, modulo, e); mpz_powm_ui(arg, arg, e, mpz_tmp); prec += v; } /* Where do we need to truncate the Taylor expansion */ N = prec+v; N /= ++v; // note the ++v Np = N; den *= v; while(1) { tmp = Np + (unsigned long)(log(N)/den); if (tmp == N) break; N = tmp; } /* We allocate memory and initialize variables */ mpz_init(f); mpz_init(mod2); mpz_init(h); mpz_init(hpow); mpz_init(d); mpz_init(inv); sig_block(); num = (mpz_t*)malloc(N*sizeof(mpz_t)); denom = (mpz_t*)malloc(N*sizeof(mpz_t)); sig_unblock(); for (i = 0; i < N; i++) { mpz_init(num[i]); mpz_init(denom[i]); } trunc = v << 1; mpz_init(trunc_mod); mpz_ui_pow_ui(trunc_mod, p, trunc); while(1) { /* We compute f = 1 - a_i*p^((v+1)*2^i) trunc_mod is p^((v+1)*2^(i+1)) */ mpz_fdiv_r(f, arg, trunc_mod); if (mpz_cmp_ui(f, 1) != 0) { mpz_ui_sub(f, 2, f); mpz_mul(arg, arg, f); /* We compute the Taylor expansion of log(f) For now, computations are carried out over the rationals */ for (i = 0; i < N; i++) { mpz_set_ui(num[i], 1); mpz_set_ui(denom[i], i+1); } step = 1; mpz_ui_sub(h, 1, f); // we write f = 1 - h, i.e. h = a_i*p^(2^i) mpz_set(hpow, h); while(step < N) { for (i = 0; i < N - step; i += step << 1) { mpz_mul(mpz_tmp2, hpow, num[i+step]); mpz_mul(mpz_tmp, mpz_tmp2, denom[i]); mpz_mul(num[i], num[i], denom[i+step]); mpz_add(num[i], num[i], mpz_tmp); mpz_mul(denom[i], denom[i], denom[i+step]); } step <<= 1; mpz_mul(hpow, hpow, hpow); } /* We simplify the fraction */ Np = N; tmp = 0; while(Np > 0) { Np /= p; tmp += Np; } mpz_ui_pow_ui(d, p, tmp); mpz_divexact(mpz_tmp, num[0], d); mpz_divexact(denom[0], denom[0], d); mpz_divexact_ui(h, h, e); mpz_mul(mpz_tmp, h, mpz_tmp); /* We coerce the result from Q to Zp */ mpz_gcdext(d, inv, NULL, denom[0], modulo); mpz_mul(mpz_tmp, mpz_tmp, inv); /* We add this contribution to log(f) */ mpz_add(ans, ans, mpz_tmp); } if (trunc > prec) break; /* We update the variables for the next step */ mpz_mul(trunc_mod, trunc_mod, trunc_mod); trunc <<= 1; for (i = N >> 1; i < N; i++) { mpz_clear(num[i]); mpz_clear(denom[i]); } N >>= 1; } mpz_fdiv_r(ans, ans, modulo); /* We clear memory */ mpz_clear(arg); mpz_clear(f); mpz_clear(trunc_mod); mpz_clear(h); mpz_clear(hpow); mpz_clear(mpz_tmp); mpz_clear(d); mpz_clear(inv); mpz_clear(mod2); for (i = 0; i < N; i++) { mpz_clear(num[i]); mpz_clear(denom[i]); } sig_block(); free(num); free(denom); sig_unblock(); }
void try_op_si (int c) { long si, oi; mpz_t sz, oz; si = c; mpz_init_set_si (sz, si); oi = si; mpz_init_set (oz, sz); do { si *= 2; /* c * 2^k */ mpz_mul_2exp (sz, sz, 1); if (check_si (sz, oz, si, oi, c)) { mpz_set (oz, sz); break; } oi = si + c; /* c * (2^k + 1) */ if (c == -1) mpz_sub_ui (oz, sz, 1); else mpz_add_ui (oz, sz, 1); if (check_si (oz, sz, oi, si, c)) break; oi = (si - c) * 2 + c; /* c * (2^K - 1) */ mpz_mul_si (oz, sz, 2*c); if (c == -1) mpz_ui_sub (oz, 1, oz); /* oz = sz * 2 + 1 */ else mpz_sub_ui (oz, oz, 1); /* oz = sz * 2 - 1 */ } while (check_si (oz, sz, oi, si, c) == 0); mpz_clear (sz); if (mpz_fits_slong_p (oz)) { printf ("Should not fit a signed long any more.\n"); printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n"); abort (); } if (mpz_cmp_si (oz, -c) != c) { printf ("mpz_cmp_si (oz, %i) != %i.\n", c, c); printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n"); abort (); } mpz_mul_2exp (oz, oz, 1); if (mpz_cmp_si (oz, -c) != c) { printf ("mpz_cmp_si (oz, %i) != %i.\n", c, c); printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n"); abort (); } mpz_clear (oz); }
int main (int argc, char **argv) { mpz_t op1, op2, r1, r2; mp_size_t op1n, op2n; unsigned long int op2long; int i; int reps = 100000; gmp_randstate_ptr rands; mpz_t bs; unsigned long bsi, size_range; tests_start (); rands = RANDS; mpz_init (bs); if (argc == 2) reps = atoi (argv[1]); mpz_init (op1); mpz_init (op2); mpz_init (r1); mpz_init (r2); for (i = 0; i < reps; i++) { mpz_urandomb (bs, rands, 32); size_range = mpz_get_ui (bs) % 10 + 2; mpz_urandomb (bs, rands, size_range); op1n = mpz_get_ui (bs); mpz_rrandomb (op1, rands, op1n); mpz_urandomb (bs, rands, size_range); op2n = mpz_get_ui (bs); mpz_rrandomb (op2, rands, op2n); mpz_urandomb (bs, rands, 2); bsi = mpz_get_ui (bs); if ((bsi & 1) != 0) mpz_neg (op1, op1); if ((bsi & 2) != 0) mpz_neg (op2, op2); /* printf ("%ld %ld\n", SIZ (multiplier), SIZ (multiplicand)); */ mpz_add (r1, op1, op2); mpz_sub (r2, r1, op2); if (mpz_cmp (r2, op1) != 0) dump_abort (i, "mpz_add or mpz_sub incorrect", op1, op2); if (mpz_fits_ulong_p (op2)) { op2long = mpz_get_ui (op2); mpz_add_ui (r1, op1, op2long); mpz_sub_ui (r2, r1, op2long); if (mpz_cmp (r2, op1) != 0) dump_abort (i, "mpz_add_ui or mpz_sub_ui incorrect", op1, op2); mpz_ui_sub (r1, op2long, op1); mpz_sub_ui (r2, op1, op2long); mpz_neg (r2, r2); if (mpz_cmp (r1, r2) != 0) dump_abort (i, "mpz_add_ui or mpz_ui_sub incorrect", op1, op2); } } mpz_clear (bs); mpz_clear (op1); mpz_clear (op2); mpz_clear (r1); mpz_clear (r2); tests_end (); exit (0); }
static PyObject * GMPy_Integer_Sub(PyObject *x, PyObject *y, CTXT_Object *context) { MPZ_Object *result; if (!(result = GMPy_MPZ_New(context))) return NULL; if (CHECK_MPZANY(x)) { if (PyIntOrLong_Check(y)) { int error; long temp = GMPy_Integer_AsLongAndError(y, &error); if (!error) { if (temp >= 0) { mpz_sub_ui(result->z, MPZ(x), temp); } else { mpz_add_ui(result->z, MPZ(x), -temp); } } else { mpz_t tempz; mpz_inoc(tempz); mpz_set_PyIntOrLong(tempz, y); mpz_sub(result->z, MPZ(x), tempz); mpz_cloc(tempz); } return (PyObject*)result; } if (CHECK_MPZANY(y)) { mpz_sub(result->z, MPZ(x), MPZ(y)); return (PyObject*)result; } } if (CHECK_MPZANY(y)) { if (PyIntOrLong_Check(x)) { int error; long temp = GMPy_Integer_AsLongAndError(x, &error); if (!error) { if (temp >= 0) { mpz_ui_sub(result->z, temp, MPZ(y)); } else { mpz_add_ui(result->z, MPZ(y), -temp); mpz_neg(result->z, result->z); } } else { mpz_t tempz; mpz_inoc(tempz); mpz_set_PyIntOrLong(tempz, x); mpz_sub(result->z, tempz, MPZ(y)); mpz_cloc(tempz); } return (PyObject*)result; } } if (IS_INTEGER(x) && IS_INTEGER(y)) { MPZ_Object *tempx, *tempy; tempx = GMPy_MPZ_From_Integer(x, context); tempy = GMPy_MPZ_From_Integer(y, context); if (!tempx || !tempy) { Py_XDECREF((PyObject*)tempx); Py_XDECREF((PyObject*)tempy); Py_DECREF((PyObject*)result); return NULL; } mpz_sub(result->z, tempx->z, tempy->z); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); return (PyObject*)result; } Py_DECREF((PyObject*)result); Py_RETURN_NOTIMPLEMENTED; }