/* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t. Uses temp1 and temp2 */ static int gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s) { /* It's not clear that gcd(0,0) is well defined, but we allow it and require that allow gcd(0,0) = 0. */ if (mpz_sgn (g) < 0) return 0; if (mpz_sgn (a) == 0) { /* Must have g == abs (b). Any value for s is in some sense "correct", but it makes sense to require that s == 0. */ return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0; } else if (mpz_sgn (b) == 0) { /* Must have g == abs (a), s == sign (a) */ return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0; } if (mpz_sgn (g) <= 0) return 0; if (! (mpz_divisible_p (a, g) && mpz_divisible_p (b, g) && mpz_cmpabs (s, b) <= 0)) return 0; mpz_mul(temp1, s, a); mpz_sub(temp1, g, temp1); mpz_tdiv_qr(temp1, temp2, temp1, b); return mpz_sgn (temp2) == 0 && mpz_cmpabs (temp1, a) <= 0; }
/* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t. Uses temp1, temp2 and temp3. */ static int gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s) { /* It's not clear that gcd(0,0) is well defined, but we allow it and require that gcd(0,0) = 0. */ if (mpz_sgn (g) < 0) return 0; if (mpz_sgn (a) == 0) { /* Must have g == abs (b). Any value for s is in some sense "correct", but it makes sense to require that s == 0. */ return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0; } else if (mpz_sgn (b) == 0) { /* Must have g == abs (a), s == sign (a) */ return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0; } if (mpz_sgn (g) <= 0) return 0; mpz_tdiv_qr (temp1, temp3, a, g); if (mpz_sgn (temp3) != 0) return 0; mpz_tdiv_qr (temp2, temp3, b, g); if (mpz_sgn (temp3) != 0) return 0; /* Require that 2 |s| < |b/g|, or |s| == 1. */ if (mpz_cmpabs_ui (s, 1) > 0) { mpz_mul_2exp (temp3, s, 1); if (mpz_cmpabs (temp3, temp2) >= 0) return 0; } /* Compute the other cofactor. */ mpz_mul(temp2, s, a); mpz_sub(temp2, g, temp2); mpz_tdiv_qr(temp2, temp3, temp2, b); if (mpz_sgn (temp3) != 0) return 0; /* Require that 2 |t| < |a/g| or |t| == 1*/ if (mpz_cmpabs_ui (temp2, 1) > 0) { mpz_mul_2exp (temp2, temp2, 1); if (mpz_cmpabs (temp2, temp1) >= 0) return 0; } return 1; }
void mpz_sqrtmn (mpz_ptr root, mpz_srcptr a, mpz_srcptr p, mpz_srcptr q, mpz_srcptr n) { mpz_t g, u, v; mpz_init(g), mpz_init(u), mpz_init(v); mpz_gcdext(g, u, v, p, q); if (mpz_cmp_ui(g, 1L) == 0) { mpz_t root_p, root_q, root1, root2, root3, root4; /* single square roots */ mpz_init(root_p), mpz_init(root_q); mpz_sqrtmp(root_p, a, p); mpz_sqrtmp(root_q, a, q); /* construct common square root */ mpz_init_set(root1, root_q); mpz_init_set(root2, root_p); mpz_init_set(root3, root_q); mpz_init_set(root4, root_p); mpz_mul(root1, root1, u); mpz_mul(root1, root1, p); mpz_mul(root2, root2, v); mpz_mul(root2, root2, q); mpz_add(root1, root1, root2); mpz_mod(root1, root1, n); mpz_sqrtmn_2(root2, root1, n); mpz_neg(root3, root3); mpz_mul(root3, root3, u); mpz_mul(root3, root3, p); mpz_mul(root4, root4, v); mpz_mul(root4, root4, q); mpz_add(root3, root3, root4); mpz_mod(root3, root3, n); mpz_sqrtmn_2 (root4, root3, n); /* choose smallest root */ mpz_set(root, root1); if (mpz_cmpabs(root2, root) < 0) mpz_set(root, root2); if (mpz_cmpabs(root3, root) < 0) mpz_set(root, root3); if (mpz_cmpabs(root4, root) < 0) mpz_set(root, root4); mpz_clear(root_p), mpz_clear(root_q); mpz_clear(root1), mpz_clear(root2); mpz_clear(root3), mpz_clear(root4); mpz_clear(g), mpz_clear(u), mpz_clear(v); return; } mpz_clear(g), mpz_clear(u), mpz_clear(v); /* error, return zero root */ mpz_set_ui(root, 0L); }
/* Called when s is supposed to be floor(root(u,z)), and r = u - s^z */ static int rootrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r, unsigned long z) { mpz_t t; mpz_init (t); if (mpz_fits_ulong_p (s)) mpz_ui_pow_ui (t, mpz_get_ui (s), z); else mpz_pow_ui (t, s, z); mpz_sub (t, u, t); if (mpz_sgn (t) != mpz_sgn(u) || mpz_cmp (t, r) != 0) { mpz_clear (t); return 0; } if (mpz_sgn (s) > 0) mpz_add_ui (t, s, 1); else mpz_sub_ui (t, s, 1); mpz_pow_ui (t, t, z); if (mpz_cmpabs (t, u) <= 0) { mpz_clear (t); return 0; } mpz_clear (t); return 1; }
void check_one (mpz_ptr x, mpz_ptr y, int want_cmp, int want_cmpabs) { int got; got = mpz_cmp (x, y); if (( got < 0) != (want_cmp < 0) || (got == 0) != (want_cmp == 0) || (got > 0) != (want_cmp > 0)) { printf ("mpz_cmp got %d want %d\n", got, want_cmp); mpz_trace ("x", x); mpz_trace ("y", y); abort (); } got = mpz_cmpabs (x, y); if (( got < 0) != (want_cmpabs < 0) || (got == 0) != (want_cmpabs == 0) || (got > 0) != (want_cmpabs > 0)) { printf ("mpz_cmpabs got %d want %d\n", got, want_cmpabs); mpz_trace ("x", x); mpz_trace ("y", y); abort (); } }
ecc_point* sum(ecc_point p1,ecc_point p2){ ecc_point* result; result = malloc(sizeof(ecc_point)); mpz_init((*result).x); mpz_init((*result).y); if (mpz_cmp(p1.x,p2.x)==0 && mpz_cmp(p1.y,p2.y)==0) result=double_p(p1); else if( mpz_cmp(p1.x,p2.x)==0 && mpz_cmpabs(p2.y,p1.y)==0) result=INFINITY_POINT; else{ mpz_t delta_x,x,y,delta_y,s,s_2; mpz_init(delta_x); mpz_init(x); mpz_init(y); mpz_init(s); mpz_init(s_2); mpz_init(delta_y); mpz_sub(delta_x,p1.x,p2.x); mpz_sub(delta_y,p1.y,p2.y); mpz_mod(delta_x,delta_x,prime); mpz_invert(delta_x,delta_x,prime); mpz_mul(s,delta_x,delta_y); mpz_mod(s,s,prime); mpz_pow_ui(s_2,s,2); mpz_sub(x,s_2,p1.x); mpz_sub(x,x,p2.x); mpz_mod(x,x,prime); mpz_set((*result).x,x); mpz_sub(delta_x,p2.x,x); mpz_neg(y,p2.y); mpz_addmul(y,s,delta_x); mpz_mod(y,y,prime); mpz_set((*result).y,y); }; return result; }
/** \brief 整系数多项式的整数根(不含重数). \param f 整系数多项式. \return 整根的list. \note 利用Zp中的根. */ void UniZRootZ_ByZp(std::vector<mpz_ptr> & rootlist,const poly_z & f) { static mpz_t A,B,p,z_temp,nA; mpz_init(A); mpz_init(B); mpz_init(p); mpz_init(z_temp); mpz_init(nA); UniMaxNormZ(A,f); uint n=f.size()-1; mpz_mul(B,A,A); mpz_add(B,B,A); mpz_mul_ui(B,B,2*n); mpz_add_ui(p,B,1); mpz_nextprime(p,p); poly_z fp,vi,ui; std::vector<mpz_ptr> ulist; uint totalroot=0; UniPolynomialMod(fp,f,p); UniZpRootZp(ulist,fp,p); mpz_mul_ui(nA,A,n); ui.resize(2); mpz_set_ui(ui[1],1); for(uint i=0; i<ulist.size(); i++) { if(mpz_cmpabs(ulist[i],A)<=0) { mpz_neg(ui[0],ulist[i]); UniDivZp(vi,fp,ui,p); UniMaxNormZ(z_temp,vi); if(mpz_cmp(z_temp,nA)<=0) { totalroot++; resize_z_list(rootlist,totalroot); mpz_set(rootlist[totalroot-1],ulist[i]); } } } mpz_clear(A); mpz_clear(B); mpz_clear(p); mpz_clear(z_temp); mpz_clear(nA); fp.resize(0); vi.resize(0); ui.resize(0); resize_z_list(ulist,0); std::sort(rootlist.begin(),rootlist.end(),mpz_ptr_less); return ; }
int fmpz_cmpabs(const fmpz_t f, const fmpz_t g) { if (f == g) return 0; /* aliased inputs */ if (!COEFF_IS_MPZ(*f)) { if (!COEFF_IS_MPZ(*g)) { mp_limb_t uf = FLINT_ABS(*f); mp_limb_t ug = FLINT_ABS(*g); return (uf < ug ? -1 : (uf > ug)); } else return -1; } else { if (!COEFF_IS_MPZ(*g)) return 1; /* f is large, so if g isn't... */ else return mpz_cmpabs(COEFF_TO_PTR(*f), COEFF_TO_PTR(*g)); } }
/* returns the number of decimal digits of n */ unsigned int b10_digits (const mpz_t n) { mpz_t x; unsigned int size; size = mpz_sizeinbase (n, 10); /* the GMP documentation says mpz_sizeinbase returns the exact value, or one too big, thus: (a) either n < 10^(size-1), and n has size-1 digits (b) or n >= size-1, and n has size digits Note: mpz_sizeinbase returns 1 for n=0, thus we always have size >= 1. */ mpz_init (x); mpz_ui_pow_ui (x, 10, size - 1); if (mpz_cmpabs (n, x) < 0) size --; mpz_clear (x); return size; }
// absCompare int32_t absCompare(const Integer &a, const Integer &b) { return mpz_cmpabs( (mpz_srcptr)&(a.gmp_rep), (mpz_srcptr)&(b.gmp_rep)); }
void spectral_test (mpf_t rop[], unsigned int T, mpz_t a, mpz_t m) { /* Knuth "Seminumerical Algorithms, Third Edition", section 3.3.4 (pp. 101-103). */ /* v[t] = min { sqrt (x[1]^2 + ... + x[t]^2) | x[1] + a*x[2] + ... + pow (a, t-1) * x[t] is congruent to 0 (mod m) } */ /* Variables. */ unsigned int ui_t; unsigned int ui_i, ui_j, ui_k, ui_l; mpf_t f_tmp1, f_tmp2; mpz_t tmp1, tmp2, tmp3; mpz_t U[GMP_SPECT_MAXT][GMP_SPECT_MAXT], V[GMP_SPECT_MAXT][GMP_SPECT_MAXT], X[GMP_SPECT_MAXT], Y[GMP_SPECT_MAXT], Z[GMP_SPECT_MAXT]; mpz_t h, hp, r, s, p, pp, q, u, v; /* GMP inits. */ mpf_init (f_tmp1); mpf_init (f_tmp2); for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++) { for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++) { mpz_init_set_ui (U[ui_i][ui_j], 0); mpz_init_set_ui (V[ui_i][ui_j], 0); } mpz_init_set_ui (X[ui_i], 0); mpz_init_set_ui (Y[ui_i], 0); mpz_init (Z[ui_i]); } mpz_init (tmp1); mpz_init (tmp2); mpz_init (tmp3); mpz_init (h); mpz_init (hp); mpz_init (r); mpz_init (s); mpz_init (p); mpz_init (pp); mpz_init (q); mpz_init (u); mpz_init (v); /* Implementation inits. */ if (T > GMP_SPECT_MAXT) T = GMP_SPECT_MAXT; /* FIXME: Lazy. */ /* S1 [Initialize.] */ ui_t = 2 - 1; /* NOTE: `t' in description == ui_t + 1 for easy indexing */ mpz_set (h, a); mpz_set (hp, m); mpz_set_ui (p, 1); mpz_set_ui (pp, 0); mpz_set (r, a); mpz_pow_ui (s, a, 2); mpz_add_ui (s, s, 1); /* s = 1 + a^2 */ /* S2 [Euclidean step.] */ while (1) { if (g_debug > DEBUG_1) { mpz_mul (tmp1, h, pp); mpz_mul (tmp2, hp, p); mpz_sub (tmp1, tmp1, tmp2); if (mpz_cmpabs (m, tmp1)) { printf ("***BUG***: h*pp - hp*p = "); mpz_out_str (stdout, 10, tmp1); printf ("\n"); } } if (g_debug > DEBUG_2) { printf ("hp = "); mpz_out_str (stdout, 10, hp); printf ("\nh = "); mpz_out_str (stdout, 10, h); printf ("\n"); fflush (stdout); } if (mpz_sgn (h)) mpz_tdiv_q (q, hp, h); /* q = floor(hp/h) */ else mpz_set_ui (q, 1); if (g_debug > DEBUG_2) { printf ("q = "); mpz_out_str (stdout, 10, q); printf ("\n"); fflush (stdout); } mpz_mul (tmp1, q, h); mpz_sub (u, hp, tmp1); /* u = hp - q*h */ mpz_mul (tmp1, q, p); mpz_sub (v, pp, tmp1); /* v = pp - q*p */ mpz_pow_ui (tmp1, u, 2); mpz_pow_ui (tmp2, v, 2); mpz_add (tmp1, tmp1, tmp2); if (mpz_cmp (tmp1, s) < 0) { mpz_set (s, tmp1); /* s = u^2 + v^2 */ mpz_set (hp, h); /* hp = h */ mpz_set (h, u); /* h = u */ mpz_set (pp, p); /* pp = p */ mpz_set (p, v); /* p = v */ } else break; } /* S3 [Compute v2.] */ mpz_sub (u, u, h); mpz_sub (v, v, p); mpz_pow_ui (tmp1, u, 2); mpz_pow_ui (tmp2, v, 2); mpz_add (tmp1, tmp1, tmp2); if (mpz_cmp (tmp1, s) < 0) { mpz_set (s, tmp1); /* s = u^2 + v^2 */ mpz_set (hp, u); mpz_set (pp, v); } mpf_set_z (f_tmp1, s); mpf_sqrt (rop[ui_t - 1], f_tmp1); /* S4 [Advance t.] */ mpz_neg (U[0][0], h); mpz_set (U[0][1], p); mpz_neg (U[1][0], hp); mpz_set (U[1][1], pp); mpz_set (V[0][0], pp); mpz_set (V[0][1], hp); mpz_neg (V[1][0], p); mpz_neg (V[1][1], h); if (mpz_cmp_ui (pp, 0) > 0) { mpz_neg (V[0][0], V[0][0]); mpz_neg (V[0][1], V[0][1]); mpz_neg (V[1][0], V[1][0]); mpz_neg (V[1][1], V[1][1]); } while (ui_t + 1 != T) /* S4 loop */ { ui_t++; mpz_mul (r, a, r); mpz_mod (r, r, m); /* Add new row and column to U and V. They are initialized with all elements set to zero, so clearing is not necessary. */ mpz_neg (U[ui_t][0], r); /* U: First col in new row. */ mpz_set_ui (U[ui_t][ui_t], 1); /* U: Last col in new row. */ mpz_set (V[ui_t][ui_t], m); /* V: Last col in new row. */ /* "Finally, for 1 <= i < t, set q = round (vi1 * r / m), vit = vi1*r - q*m, and Ut=Ut+q*Ui */ for (ui_i = 0; ui_i < ui_t; ui_i++) { mpz_mul (tmp1, V[ui_i][0], r); /* tmp1=vi1*r */ zdiv_round (q, tmp1, m); /* q=round(vi1*r/m) */ mpz_mul (tmp2, q, m); /* tmp2=q*m */ mpz_sub (V[ui_i][ui_t], tmp1, tmp2); for (ui_j = 0; ui_j <= ui_t; ui_j++) /* U[t] = U[t] + q*U[i] */ { mpz_mul (tmp1, q, U[ui_i][ui_j]); /* tmp=q*uij */ mpz_add (U[ui_t][ui_j], U[ui_t][ui_j], tmp1); /* utj = utj + q*uij */ } } /* s = min (s, zdot (U[t], U[t]) */ vz_dot (tmp1, U[ui_t], U[ui_t], ui_t + 1); if (mpz_cmp (tmp1, s) < 0) mpz_set (s, tmp1); ui_k = ui_t; ui_j = 0; /* WARNING: ui_j no longer a temp. */ /* S5 [Transform.] */ if (g_debug > DEBUG_2) printf ("(t, k, j, q1, q2, ...)\n"); do { if (g_debug > DEBUG_2) printf ("(%u, %u, %u", ui_t + 1, ui_k + 1, ui_j + 1); for (ui_i = 0; ui_i <= ui_t; ui_i++) { if (ui_i != ui_j) { vz_dot (tmp1, V[ui_i], V[ui_j], ui_t + 1); /* tmp1=dot(Vi,Vj). */ mpz_abs (tmp2, tmp1); mpz_mul_ui (tmp2, tmp2, 2); /* tmp2 = 2*abs(dot(Vi,Vj) */ vz_dot (tmp3, V[ui_j], V[ui_j], ui_t + 1); /* tmp3=dot(Vj,Vj). */ if (mpz_cmp (tmp2, tmp3) > 0) { zdiv_round (q, tmp1, tmp3); /* q=round(Vi.Vj/Vj.Vj) */ if (g_debug > DEBUG_2) { printf (", "); mpz_out_str (stdout, 10, q); } for (ui_l = 0; ui_l <= ui_t; ui_l++) { mpz_mul (tmp1, q, V[ui_j][ui_l]); mpz_sub (V[ui_i][ui_l], V[ui_i][ui_l], tmp1); /* Vi=Vi-q*Vj */ mpz_mul (tmp1, q, U[ui_i][ui_l]); mpz_add (U[ui_j][ui_l], U[ui_j][ui_l], tmp1); /* Uj=Uj+q*Ui */ } vz_dot (tmp1, U[ui_j], U[ui_j], ui_t + 1); /* tmp1=dot(Uj,Uj) */ if (mpz_cmp (tmp1, s) < 0) /* s = min(s,dot(Uj,Uj)) */ mpz_set (s, tmp1); ui_k = ui_j; } else if (g_debug > DEBUG_2) printf (", #"); /* 2|Vi.Vj| <= Vj.Vj */ } else if (g_debug > DEBUG_2) printf (", *"); /* i == j */ } if (g_debug > DEBUG_2) printf (")\n"); /* S6 [Advance j.] */ if (ui_j == ui_t) ui_j = 0; else ui_j++; } while (ui_j != ui_k); /* S5 */ /* From Knuth p. 104: "The exhaustive search in steps S8-S10 reduces the value of s only rarely." */ #ifdef DO_SEARCH /* S7 [Prepare for search.] */ /* Find minimum in (x[1], ..., x[t]) satisfying condition x[k]^2 <= f(y[1], ...,y[t]) * dot(V[k],V[k]) */ ui_k = ui_t; if (g_debug > DEBUG_2) { printf ("searching..."); /*for (f = 0; f < ui_t*/ fflush (stdout); } /* Z[i] = floor (sqrt (floor (dot(V[i],V[i]) * s / m^2))); */ mpz_pow_ui (tmp1, m, 2); mpf_set_z (f_tmp1, tmp1); mpf_set_z (f_tmp2, s); mpf_div (f_tmp1, f_tmp2, f_tmp1); /* f_tmp1 = s/m^2 */ for (ui_i = 0; ui_i <= ui_t; ui_i++) { vz_dot (tmp1, V[ui_i], V[ui_i], ui_t + 1); mpf_set_z (f_tmp2, tmp1); mpf_mul (f_tmp2, f_tmp2, f_tmp1); f_floor (f_tmp2, f_tmp2); mpf_sqrt (f_tmp2, f_tmp2); mpz_set_f (Z[ui_i], f_tmp2); } /* S8 [Advance X[k].] */ do { if (g_debug > DEBUG_2) { printf ("X[%u] = ", ui_k); mpz_out_str (stdout, 10, X[ui_k]); printf ("\tZ[%u] = ", ui_k); mpz_out_str (stdout, 10, Z[ui_k]); printf ("\n"); fflush (stdout); } if (mpz_cmp (X[ui_k], Z[ui_k])) { mpz_add_ui (X[ui_k], X[ui_k], 1); for (ui_i = 0; ui_i <= ui_t; ui_i++) mpz_add (Y[ui_i], Y[ui_i], U[ui_k][ui_i]); /* S9 [Advance k.] */ while (++ui_k <= ui_t) { mpz_neg (X[ui_k], Z[ui_k]); mpz_mul_ui (tmp1, Z[ui_k], 2); for (ui_i = 0; ui_i <= ui_t; ui_i++) { mpz_mul (tmp2, tmp1, U[ui_k][ui_i]); mpz_sub (Y[ui_i], Y[ui_i], tmp2); } } vz_dot (tmp1, Y, Y, ui_t + 1); if (mpz_cmp (tmp1, s) < 0) mpz_set (s, tmp1); } } while (--ui_k); #endif /* DO_SEARCH */ mpf_set_z (f_tmp1, s); mpf_sqrt (rop[ui_t - 1], f_tmp1); #ifdef DO_SEARCH if (g_debug > DEBUG_2) printf ("done.\n"); #endif /* DO_SEARCH */ } /* S4 loop */ /* Clear GMP variables. */ mpf_clear (f_tmp1); mpf_clear (f_tmp2); for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++) { for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++) { mpz_clear (U[ui_i][ui_j]); mpz_clear (V[ui_i][ui_j]); } mpz_clear (X[ui_i]); mpz_clear (Y[ui_i]); mpz_clear (Z[ui_i]); } mpz_clear (tmp1); mpz_clear (tmp2); mpz_clear (tmp3); mpz_clear (h); mpz_clear (hp); mpz_clear (r); mpz_clear (s); mpz_clear (p); mpz_clear (pp); mpz_clear (q); mpz_clear (u); mpz_clear (v); return; }
void check_one (mpz_t root1, mpz_t x2, unsigned long nth, int i) { mpz_t temp, temp2; mpz_t root2, rem2; mpz_init (root2); mpz_init (rem2); mpz_init (temp); mpz_init (temp2); MPZ_CHECK_FORMAT (root1); mpz_rootrem (root2, rem2, x2, nth); MPZ_CHECK_FORMAT (root2); MPZ_CHECK_FORMAT (rem2); mpz_pow_ui (temp, root1, nth); MPZ_CHECK_FORMAT (temp); mpz_add (temp2, temp, rem2); /* Is power of result > argument? */ if (mpz_cmp (root1, root2) != 0 || mpz_cmp (x2, temp2) != 0 || mpz_cmpabs (temp, x2) > 0) { fprintf (stderr, "ERROR after test %d\n", i); debug_mp (x2, 10); debug_mp (root1, 10); debug_mp (root2, 10); fprintf (stderr, "nth: %lu\n", nth); abort (); } if (nth > 1 && mpz_cmp_ui (temp, 1L) > 0 && ! mpz_perfect_power_p (temp)) { fprintf (stderr, "ERROR in mpz_perfect_power_p after test %d\n", i); debug_mp (temp, 10); debug_mp (root1, 10); fprintf (stderr, "nth: %lu\n", nth); abort (); } if (nth <= 10000 && mpz_sgn(x2) > 0) /* skip too expensive test */ { mpz_add_ui (temp2, root1, 1L); mpz_pow_ui (temp2, temp2, nth); MPZ_CHECK_FORMAT (temp2); /* Is square of (result + 1) <= argument? */ if (mpz_cmp (temp2, x2) <= 0) { fprintf (stderr, "ERROR after test %d\n", i); debug_mp (x2, 10); debug_mp (root1, 10); fprintf (stderr, "nth: %lu\n", nth); abort (); } } mpz_clear (root2); mpz_clear (rem2); mpz_clear (temp); mpz_clear (temp2); }
/* *********************************************************************************************** * mpz_selfridge_prp: * A "Lucas-Selfridge pseudoprime" n is a "Lucas pseudoprime" using Selfridge parameters of: * Find the first element D in the sequence {5, -7, 9, -11, 13, ...} such that Jacobi(D,n) = -1 * Then use P=1 and Q=(1-D)/4 in the Lucas pseudoprime test. * Make sure n is not a perfect square, otherwise the search for D will only stop when D=n. * ***********************************************************************************************/ int mpz_selfridge_prp(mpz_t n) { long int d = 5, p = 1, q = 0; int max_d = 1000000; int jacobi = 0; mpz_t zD; if (mpz_cmp_ui(n, 2) < 0) return PRP_COMPOSITE; if (mpz_divisible_ui_p(n, 2)) { if (mpz_cmp_ui(n, 2) == 0) return PRP_PRIME; else return PRP_COMPOSITE; } mpz_init_set_ui(zD, d); while (1) { jacobi = mpz_jacobi(zD, n); /* if jacobi == 0, d is a factor of n, therefore n is composite... */ /* if d == n, then either n is either prime or 9... */ if (jacobi == 0) { if ((mpz_cmpabs(zD, n) == 0) && (mpz_cmp_ui(zD, 9) != 0)) { mpz_clear(zD); return PRP_PRIME; } else { mpz_clear(zD); return PRP_COMPOSITE; } } if (jacobi == -1) break; /* if we get to the 5th d, make sure we aren't dealing with a square... */ if (d == 13) { if (mpz_perfect_square_p(n)) { mpz_clear(zD); return PRP_COMPOSITE; } } if (d < 0) { d *= -1; d += 2; } else { d += 2; d *= -1; } /* make sure we don't search forever */ if (d >= max_d) { mpz_clear(zD); return PRP_ERROR; } mpz_set_si(zD, d); } mpz_clear(zD); q = (1-d)/4; return mpz_lucas_prp(n, p, q); }/* method mpz_selfridge_prp */
static PyObject * GMPY_mpz_is_strongselfridge_prp(PyObject *self, PyObject *args) { MPZ_Object *n; PyObject *result = 0, *temp = 0; long d = 5, p = 1, q = 0, max_d = 1000000; int jacobi = 0; mpz_t zD; if (PyTuple_Size(args) != 1) { TYPE_ERROR("is_strong_selfridge_prp() requires 1 integer argument"); return NULL; } mpz_init(zD); n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); if (!n) { TYPE_ERROR("is_strong_selfridge_prp() requires 1 integer argument"); goto cleanup; } /* Require n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("is_strong_selfridge_prp() requires 'n' be greater than 0"); goto cleanup; } /* Check for n == 1 */ if (mpz_cmp_ui(n->z, 1) == 0) { result = Py_False; goto cleanup; } /* Handle n even. */ if (mpz_divisible_ui_p(n->z, 2)) { if (mpz_cmp_ui(n->z, 2) == 0) result = Py_True; else result = Py_False; goto cleanup; } mpz_set_ui(zD, d); while (1) { jacobi = mpz_jacobi(zD, n->z); /* if jacobi == 0, d is a factor of n, therefore n is composite... */ /* if d == n, then either n is either prime or 9... */ if (jacobi == 0) { if ((mpz_cmpabs(zD, n->z) == 0) && (mpz_cmp_ui(zD, 9) != 0)) { result = Py_True; goto cleanup; } else { result = Py_False; goto cleanup; } } if (jacobi == -1) break; /* if we get to the 5th d, make sure we aren't dealing with a square... */ if (d == 13) { if (mpz_perfect_square_p(n->z)) { result = Py_False; goto cleanup; } } if (d < 0) { d *= -1; d += 2; } else { d += 2; d *= -1; } /* make sure we don't search forever */ if (d >= max_d) { VALUE_ERROR("appropriate value for D cannot be found in is_strong_selfridge_prp()"); goto cleanup; } mpz_set_si(zD, d); } q = (1-d)/4; /* Since "O" is used, the refcount for n is incremented so deleting * temp will not delete n. */ temp = Py_BuildValue("Oll", n, p, q); if (!temp) goto cleanup; result = GMPY_mpz_is_stronglucas_prp(NULL, temp); Py_DECREF(temp); goto return_result; cleanup: Py_XINCREF(result); return_result: mpz_clear(zD); Py_DECREF((PyObject*)n); return result; }
unsigned long combine_large_primes(QS_t * qs_inf, linalg_t * la_inf, poly_t * poly_inf, FILE *COMB, mpz_t factor) { char new_relation[MPQS_STRING_LENGTH], buf[MPQS_STRING_LENGTH]; mpqs_lp_entry e[2]; /* we'll use the two alternatingly */ unsigned long *ei; long ei_size = qs_inf->num_primes; mpz_t * N = &qs_inf->mpz_n; long old_q; mpz_t inv_q, Y1, Y2, new_Y, new_Y1; mpz_init(inv_q); mpz_init(Y1); mpz_init(Y2); mpz_init(new_Y); mpz_init(new_Y1); long i, l, c = 0; unsigned long newrels = 0; if (!fgets(buf, MPQS_STRING_LENGTH, COMB)) return 0; /* should not happen */ ei = (unsigned long *) malloc(sizeof(unsigned long)*ei_size); /* put first lp relation in row 0 of e */ set_lp_entry(&e[0], buf); i = 1; /* second relation will go into row 1 */ old_q = e[0].q; mpz_set_ui(inv_q, old_q); while (!mpz_invert(inv_q, inv_q, *N)) /* can happen */ { /* We have found a factor. It could be N when N is quite small; or we might just have found a divisor by sheer luck. */ mpz_gcd_ui(inv_q, *N, old_q); if (!mpz_cmp(inv_q, *N)) /* pity */ { if (!fgets(buf, MPQS_STRING_LENGTH, COMB)) { return 0; } set_lp_entry(&e[0], buf); old_q = e[0].q; mpz_set_ui(inv_q, old_q); continue; } mpz_set(factor, inv_q); free(ei); mpz_clear(inv_q); mpz_clear(Y1); mpz_clear(Y2); mpz_clear(new_Y); mpz_clear(new_Y1); return c; } gmp_sscanf(e[0].Y, "%Zd", Y1); while (fgets(buf, MPQS_STRING_LENGTH, COMB)) { set_lp_entry(&e[i], buf); if (e[i].q != old_q) { /* switch to combining a new bunch, swapping the rows */ old_q = e[i].q; mpz_set_ui(inv_q, old_q); while (!mpz_invert(inv_q, inv_q, *N)) /* can happen */ { mpz_gcd_ui(inv_q, *N, old_q); if (!mpz_cmp(inv_q, *N)) /* pity */ { old_q = -1; /* sentinel */ continue; /* discard this combination */ } mpz_set(factor, inv_q); free(ei); mpz_clear(inv_q); mpz_clear(Y1); mpz_clear(Y2); mpz_clear(new_Y); mpz_clear(new_Y1); return c; } gmp_sscanf(e[i].Y, "%Zd", Y1); i = 1 - i; /* subsequent relations go to other row */ continue; } /* count and combine the two we've got, and continue in the same row */ memset((void *)ei, 0, ei_size * sizeof(long)); set_exponents(ei, e[0].E); set_exponents(ei, e[1].E); gmp_sscanf(e[i].Y, "%Zd", Y2); if (mpz_cmpabs(Y1,Y2)!=0) { unsigned long * small = la_inf->small; fac_t * factor = la_inf->factor; unsigned long num_factors = 0; unsigned long small_primes = qs_inf->small_primes; unsigned long num_primes = qs_inf->num_primes; c++; mpz_mul(new_Y, Y1, Y2); mpz_mul(new_Y, new_Y, inv_q); mpz_mod(new_Y, new_Y, *N); mpz_sub(new_Y1, *N, new_Y); if (mpz_cmpabs(new_Y1, new_Y) < 0) mpz_set(new_Y, new_Y1); for (l = 0; l < small_primes; l++) { small[l] = ei[l]; } for (l = small_primes; l < num_primes; l++) { if (ei[l]) { factor[num_factors].ind = l; factor[num_factors].exp = ei[l]; num_factors++; } } la_inf->num_factors = num_factors; newrels += insert_relation(qs_inf, la_inf, poly_inf, new_Y); } } /* while */ free(ei); mpz_clear(inv_q); mpz_clear(Y1); mpz_clear(Y2); mpz_clear(new_Y); mpz_clear(new_Y1); return newrels; }
static int pol_expand(curr_poly_t *c, mpz_t gmp_N, mpz_t high_coeff, mpz_t gmp_p, mpz_t gmp_d, double coeff_bound, uint32 degree) { uint32 i, j; if (mpz_cmp_ui(c->gmp_p, (mp_limb_t)1) == 0) mpz_set_ui(c->gmp_help1, (mp_limb_t)1); else { if (!mpz_invert(c->gmp_help1, gmp_d, gmp_p)) return 0; } mpz_set(c->gmp_b[1], c->gmp_help1); for (i = 2; i < degree; i++) mpz_mul(c->gmp_b[i], c->gmp_b[i-1], c->gmp_help1); mpz_set(c->gmp_c[1], gmp_d); for (i = 2; i <= degree; i++) mpz_mul(c->gmp_c[i], c->gmp_c[i-1], gmp_d); mpz_set(c->gmp_a[degree], high_coeff); mpz_set(c->gmp_help2, gmp_N); for (i = degree - 1; (int32)i >= 0; i--) { mpz_mul(c->gmp_help3, c->gmp_a[i+1], c->gmp_c[i+1]); mpz_sub(c->gmp_help3, c->gmp_help2, c->gmp_help3); mpz_tdiv_q(c->gmp_help2, c->gmp_help3, gmp_p); if (i > 0) { mpz_tdiv_q(c->gmp_a[i], c->gmp_help2, c->gmp_c[i]); mpz_mul(c->gmp_help3, c->gmp_help2, c->gmp_b[i]); mpz_sub(c->gmp_help3, c->gmp_help3, c->gmp_a[i]); mpz_tdiv_r(c->gmp_help4, c->gmp_help3, gmp_p); if (mpz_sgn(c->gmp_help4) < 0) mpz_add(c->gmp_help4, c->gmp_help4, gmp_p); mpz_add(c->gmp_a[i], c->gmp_a[i], c->gmp_help4); } } mpz_set(c->gmp_a[0], c->gmp_help2); mpz_tdiv_q_2exp(c->gmp_help1, gmp_d, (mp_limb_t)1); for (i = 0; i < degree; i++) { for (j = 0; j < MAX_CORRECT_STEPS && mpz_cmpabs(c->gmp_a[i], c->gmp_help1) > 0; j++) { if (mpz_sgn(c->gmp_a[i]) < 0) { mpz_add(c->gmp_a[i], c->gmp_a[i], gmp_d); mpz_sub(c->gmp_a[i+1], c->gmp_a[i+1], gmp_p); } else { mpz_sub(c->gmp_a[i], c->gmp_a[i], gmp_d); mpz_add(c->gmp_a[i+1], c->gmp_a[i+1], gmp_p); } } if (j == MAX_CORRECT_STEPS) return 0; } #if 0 gmp_printf("%+Zd\n", c->gmp_lina[0]); gmp_printf("%+Zd\n", c->gmp_lina[1]); for (i = 0; i <= degree; i++) gmp_printf("%+Zd\n", c->gmp_a[i]); printf("coeff ratio = %.5lf\n", fabs(mpz_get_d(c->gmp_a[degree-2])) / coeff_bound); #endif if (check_poly(c, c->gmp_a, c->gmp_lina[0], gmp_N, degree) != 1) { return 0; } if (mpz_cmpabs_d(c->gmp_a[degree - 2], coeff_bound) > 0) { return 1; } return 2; }
AlkValue AlkValue::convertDenominator(int _denom, const RoundingMethod how) const { AlkValue in(*this); mpz_class in_num(mpq_numref(in.d->m_val.get_mpq_t())); AlkValue out; // initialize to zero int sign = sgn(in_num); if (sign != 0) { // sign is either -1 for negative numbers or +1 in all other cases AlkValue temp; mpz_class denom = _denom; // only process in case the denominators are different if (mpz_cmpabs(denom.get_mpz_t(), mpq_denref(d->m_val.get_mpq_t())) != 0) { mpz_class in_denom(mpq_denref(in.d->m_val.get_mpq_t())); mpz_class out_num, out_denom; if (sgn(in_denom) == -1) { // my denom is negative in_num = in_num * (- in_denom); in_num = 1; } mpz_class remainder; int denom_neg = 0; // if the denominator is less than zero, we are to interpret it as // the reciprocal of its magnitude. if (sgn(denom) < 0) { mpz_class temp_a; mpz_class temp_bc; denom = -denom; denom_neg = 1; temp_a = ::abs(in_num); temp_bc = in_denom * denom; remainder = temp_a % temp_bc; out_num = temp_a / temp_bc; out_denom = denom; } else { temp = AlkValue(denom, in_denom); // the canonicalization required here is part of the ctor // temp.d->m_val.canonicalize(); out_num = ::abs(in_num * temp.d->m_val.get_num()); remainder = out_num % temp.d->m_val.get_den(); out_num = out_num / temp.d->m_val.get_den(); out_denom = denom; } if (remainder != 0) { switch (how) { case RoundFloor: if (sign < 0) { out_num = out_num + 1; } break; case RoundCeil: if (sign > 0) { out_num = out_num + 1; } break; case RoundTruncate: break; case RoundPromote: out_num = out_num + 1; break; case RoundHalfDown: if (denom_neg) { if ((2 * remainder) > (in_denom * denom)) { out_num = out_num + 1; } } else if ((2 * remainder) > (temp.d->m_val.get_den())) { out_num = out_num + 1; } break; case RoundHalfUp: if (denom_neg) { if ((2 * remainder) >= (in_denom * denom)) { out_num = out_num + 1; } } else if ((2 * remainder) >= temp.d->m_val.get_den()) { out_num = out_num + 1; } break; case RoundRound: if (denom_neg) { if ((remainder * 2) > (in_denom * denom)) { out_num = out_num + 1; } else if ((2 * remainder) == (in_denom * denom)) { if ((out_num % 2) != 0) { out_num = out_num + 1; } } } else { if ((remainder * 2) > temp.d->m_val.get_den()) { out_num = out_num + 1; } else if ((2 * remainder) == temp.d->m_val.get_den()) { if ((out_num % 2) != 0) { out_num = out_num + 1; } } } break; case RoundNever: qWarning("AlkValue: have remainder \"%s\"->convert(%d, %d)", qPrintable(toString()), _denom, how); break; } } // construct the new output value out = AlkValue(out_num * sign, out_denom); } else { out = *this; } } return out; }
void check_one (mpz_srcptr a, unsigned long d) { mpz_t q, r, p, d2exp; int inplace; mpz_init (d2exp); mpz_init (q); mpz_init (r); mpz_init (p); mpz_set_ui (d2exp, 1L); mpz_mul_2exp (d2exp, d2exp, d); #define INPLACE(fun,dst,src,d) \ if (inplace) \ { \ mpz_set (dst, src); \ fun (dst, dst, d); \ } \ else \ fun (dst, src, d); for (inplace = 0; inplace <= 1; inplace++) { INPLACE (mpz_fdiv_q_2exp, q, a, d); INPLACE (mpz_fdiv_r_2exp, r, a, d); mpz_mul_2exp (p, q, d); mpz_add (p, p, r); if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0) { printf ("mpz_fdiv_r_2exp result out of range\n"); goto error; } if (mpz_cmp (p, a) != 0) { printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n"); goto error; } INPLACE (mpz_cdiv_q_2exp, q, a, d); INPLACE (mpz_cdiv_r_2exp, r, a, d); mpz_mul_2exp (p, q, d); mpz_add (p, p, r); if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0) { printf ("mpz_cdiv_r_2exp result out of range\n"); goto error; } if (mpz_cmp (p, a) != 0) { printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n"); goto error; } INPLACE (mpz_tdiv_q_2exp, q, a, d); INPLACE (mpz_tdiv_r_2exp, r, a, d); mpz_mul_2exp (p, q, d); mpz_add (p, p, r); if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a)) { printf ("mpz_tdiv_r_2exp result wrong sign\n"); goto error; } if (mpz_cmpabs (r, d2exp) >= 0) { printf ("mpz_tdiv_r_2exp result out of range\n"); goto error; } if (mpz_cmp (p, a) != 0) { printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n"); goto error; } } mpz_clear (d2exp); mpz_clear (q); mpz_clear (r); mpz_clear (p); return; error: mpz_trace ("a", a); printf ("d=%lu\n", d); mpz_trace ("q", q); mpz_trace ("r", r); mpz_trace ("p", p); mp_trace_base = -16; mpz_trace ("a", a); printf ("d=0x%lX\n", d); mpz_trace ("q", q); mpz_trace ("r", r); mpz_trace ("p", p); abort (); }
void run_setup(int num_constraints, int num_inputs, int num_outputs, int num_vars, mpz_t p, string vkey_file, string pkey_file, string unprocessed_vkey_file) { std::ifstream Amat("./bin/" + std::string(NAME) + ".qap.matrix_a"); std::ifstream Bmat("./bin/" + std::string(NAME) + ".qap.matrix_b"); std::ifstream Cmat("./bin/" + std::string(NAME) + ".qap.matrix_c"); libsnark::default_r1cs_gg_ppzksnark_pp::init_public_params(); libsnark::r1cs_constraint_system<FieldT> q; int Ai, Aj, Bi, Bj, Ci, Cj; mpz_t Acoef, Bcoef, Ccoef; mpz_init(Acoef); mpz_init(Bcoef); mpz_init(Ccoef); Amat >> Ai; Amat >> Aj; Amat >> Acoef; if (mpz_cmpabs(Acoef, p) > 0) { gmp_printf("WARNING: Coefficient larger than prime (%Zd > %Zd).\n", Acoef, p); mpz_mod(Acoef, Acoef, p); } if (mpz_sgn(Acoef) == -1) { mpz_add(Acoef, p, Acoef); } // std::cout << Ai << " " << Aj << " " << Acoef << std::std::endl; Bmat >> Bi; Bmat >> Bj; Bmat >> Bcoef; if (mpz_cmpabs(Bcoef, p) > 0) { gmp_printf("WARNING: Coefficient larger than prime (%Zd > %Zd).\n", Bcoef, p); mpz_mod(Bcoef, Bcoef, p); } if (mpz_sgn(Bcoef) == -1) { mpz_add(Bcoef, p, Bcoef); } Cmat >> Ci; Cmat >> Cj; Cmat >> Ccoef; if (mpz_cmpabs(Ccoef, p) > 0) { gmp_printf("WARNING: Coefficient larger than prime (%Zd > %Zd).\n", Ccoef, p); mpz_mod(Ccoef, Ccoef, p); } if (mpz_sgn(Ccoef) == -1) { mpz_mul_si(Ccoef, Ccoef, -1); } else if(mpz_sgn(Ccoef) == 1) { mpz_mul_si(Ccoef, Ccoef, -1); mpz_add(Ccoef, p, Ccoef); } int num_intermediate_vars = num_vars; int num_inputs_outputs = num_inputs + num_outputs; q.primary_input_size = num_inputs_outputs; q.auxiliary_input_size = num_intermediate_vars; for (int currentconstraint = 1; currentconstraint <= num_constraints; currentconstraint++) { libsnark::linear_combination<FieldT> A, B, C; while(Aj == currentconstraint && Amat) { if (Ai <= num_intermediate_vars && Ai != 0) { Ai += num_inputs_outputs; } else if (Ai > num_intermediate_vars) { Ai -= num_intermediate_vars; } FieldT AcoefT(Acoef); A.add_term(Ai, AcoefT); if(!Amat) { break; } Amat >> Ai; Amat >> Aj; Amat >> Acoef; if (mpz_cmpabs(Acoef, p) > 0) { gmp_printf("WARNING: Coefficient larger than prime (%Zd > %Zd).\n", Acoef, p); mpz_mod(Acoef, Acoef, p); } if (mpz_sgn(Acoef) == -1) { mpz_add(Acoef, p, Acoef); } } while(Bj == currentconstraint && Bmat) { if (Bi <= num_intermediate_vars && Bi != 0) { Bi += num_inputs_outputs; } else if (Bi > num_intermediate_vars) { Bi -= num_intermediate_vars; } // std::cout << Bi << " " << Bj << " " << Bcoef << std::std::endl; FieldT BcoefT(Bcoef); B.add_term(Bi, BcoefT); if (!Bmat) { break; } Bmat >> Bi; Bmat >> Bj; Bmat >> Bcoef; if (mpz_cmpabs(Bcoef, p) > 0) { gmp_printf("WARNING: Coefficient larger than prime (%Zd > %Zd).\n", Bcoef, p); mpz_mod(Bcoef, Bcoef, p); } if (mpz_sgn(Bcoef) == -1) { mpz_add(Bcoef, p, Bcoef); } } while(Cj == currentconstraint && Cmat) { if (Ci <= num_intermediate_vars && Ci != 0) { Ci += num_inputs_outputs; } else if (Ci > num_intermediate_vars) { Ci -= num_intermediate_vars; } //Libsnark constraints are A*B = C, vs. A*B - C = 0 for Zaatar. //Which is why the C coefficient is negated. // std::cout << Ci << " " << Cj << " " << Ccoef << std::std::endl; FieldT CcoefT(Ccoef); C.add_term(Ci, CcoefT); if (!Cmat) { break; } Cmat >> Ci; Cmat >> Cj; Cmat >> Ccoef; if (mpz_cmpabs(Ccoef, p) > 0) { gmp_printf("WARNING: Coefficient larger than prime (%Zd > %Zd).\n", Ccoef, p); mpz_mod(Ccoef, Ccoef, p); } if (mpz_sgn(Ccoef) == -1) { mpz_mul_si(Ccoef, Ccoef, -1); } else if (mpz_sgn(Ccoef) == 1) { mpz_mul_si(Ccoef, Ccoef, -1); mpz_add(Ccoef, p, Ccoef); } } q.add_constraint(libsnark::r1cs_constraint<FieldT>(A, B, C)); //dump_constraint(r1cs_constraint<FieldT>(A, B, C), va, variable_annotations); } Amat.close(); Bmat.close(); Cmat.close(); libff::start_profiling(); libsnark::r1cs_gg_ppzksnark_keypair<libsnark::default_r1cs_gg_ppzksnark_pp> keypair = libsnark::r1cs_gg_ppzksnark_generator<libsnark::default_r1cs_gg_ppzksnark_pp>(q); libsnark::r1cs_gg_ppzksnark_processed_verification_key<libsnark::default_r1cs_gg_ppzksnark_pp> pvk = libsnark::r1cs_gg_ppzksnark_verifier_process_vk<libsnark::default_r1cs_gg_ppzksnark_pp>(keypair.vk); std::ofstream vkey(vkey_file); std::ofstream pkey(pkey_file); vkey << pvk; pkey << keypair.pk; pkey.close(); vkey.close(); if (unprocessed_vkey_file.length() > 0) { std::ofstream unprocessed_vkey(unprocessed_vkey_file); unprocessed_vkey << keypair.vk; unprocessed_vkey.close(); } }
static int mpfr_rem1 (mpfr_ptr rem, long *quo, mpfr_rnd_t rnd_q, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd) { mpfr_exp_t ex, ey; int compare, inex, q_is_odd, sign, signx = MPFR_SIGN (x); mpz_t mx, my, r; int tiny = 0; MPFR_ASSERTD (rnd_q == MPFR_RNDN || rnd_q == MPFR_RNDZ); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x) || MPFR_IS_SINGULAR (y))) { if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y) || MPFR_IS_INF (x) || MPFR_IS_ZERO (y)) { /* for remquo, quo is undefined */ MPFR_SET_NAN (rem); MPFR_RET_NAN; } else /* either y is Inf and x is 0 or non-special, or x is 0 and y is non-special, in both cases the quotient is zero. */ { if (quo) *quo = 0; return mpfr_set (rem, x, rnd); } } /* now neither x nor y is NaN, Inf or zero */ mpz_init (mx); mpz_init (my); mpz_init (r); ex = mpfr_get_z_2exp (mx, x); /* x = mx*2^ex */ ey = mpfr_get_z_2exp (my, y); /* y = my*2^ey */ /* to get rid of sign problems, we compute it separately: quo(-x,-y) = quo(x,y), rem(-x,-y) = -rem(x,y) quo(-x,y) = -quo(x,y), rem(-x,y) = -rem(x,y) thus quo = sign(x/y)*quo(|x|,|y|), rem = sign(x)*rem(|x|,|y|) */ sign = (signx == MPFR_SIGN (y)) ? 1 : -1; mpz_abs (mx, mx); mpz_abs (my, my); q_is_odd = 0; /* divide my by 2^k if possible to make operations mod my easier */ { unsigned long k = mpz_scan1 (my, 0); ey += k; mpz_fdiv_q_2exp (my, my, k); } if (ex <= ey) { /* q = x/y = mx/(my*2^(ey-ex)) */ /* First detect cases where q=0, to avoid creating a huge number my*2^(ey-ex): if sx = mpz_sizeinbase (mx, 2) and sy = mpz_sizeinbase (my, 2), we have x < 2^(ex + sx) and y >= 2^(ey + sy - 1), thus if ex + sx <= ey + sy - 1 the quotient is 0 */ if (ex + (mpfr_exp_t) mpz_sizeinbase (mx, 2) < ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) { tiny = 1; mpz_set (r, mx); mpz_set_ui (mx, 0); } else { mpz_mul_2exp (my, my, ey - ex); /* divide mx by my*2^(ey-ex) */ /* since mx > 0 and my > 0, we can use mpz_tdiv_qr in all cases */ mpz_tdiv_qr (mx, r, mx, my); /* 0 <= |r| <= |my|, r has the same sign as mx */ } if (rnd_q == MPFR_RNDN) q_is_odd = mpz_tstbit (mx, 0); if (quo) /* mx is the quotient */ { mpz_tdiv_r_2exp (mx, mx, WANTED_BITS); *quo = mpz_get_si (mx); } } else /* ex > ey */ { if (quo) /* remquo case */ /* for remquo, to get the low WANTED_BITS more bits of the quotient, we first compute R = X mod Y*2^WANTED_BITS, where X and Y are defined below. Then the low WANTED_BITS of the quotient are floor(R/Y). */ mpz_mul_2exp (my, my, WANTED_BITS); /* 2^WANTED_BITS*Y */ else if (rnd_q == MPFR_RNDN) /* remainder case */ /* Let X = mx*2^(ex-ey) and Y = my. Then both X and Y are integers. Assume X = R mod Y, then x = X*2^ey = R*2^ey mod (Y*2^ey=y). To be able to perform the rounding, we need the least significant bit of the quotient, i.e., one more bit in the remainder, which is obtained by dividing by 2Y. */ mpz_mul_2exp (my, my, 1); /* 2Y */ mpz_set_ui (r, 2); mpz_powm_ui (r, r, ex - ey, my); /* 2^(ex-ey) mod my */ mpz_mul (r, r, mx); mpz_mod (r, r, my); if (quo) /* now 0 <= r < 2^WANTED_BITS*Y */ { mpz_fdiv_q_2exp (my, my, WANTED_BITS); /* back to Y */ mpz_tdiv_qr (mx, r, r, my); /* oldr = mx*my + newr */ *quo = mpz_get_si (mx); q_is_odd = *quo & 1; } else if (rnd_q == MPFR_RNDN) /* now 0 <= r < 2Y in the remainder case */ { mpz_fdiv_q_2exp (my, my, 1); /* back to Y */ /* least significant bit of q */ q_is_odd = mpz_cmpabs (r, my) >= 0; if (q_is_odd) mpz_sub (r, r, my); } /* now 0 <= |r| < |my|, and if needed, q_is_odd is the least significant bit of q */ } if (mpz_cmp_ui (r, 0) == 0) { inex = mpfr_set_ui (rem, 0, MPFR_RNDN); /* take into account sign of x */ if (signx < 0) mpfr_neg (rem, rem, MPFR_RNDN); } else { if (rnd_q == MPFR_RNDN) { /* FIXME: the comparison 2*r < my could be done more efficiently at the mpn level */ mpz_mul_2exp (r, r, 1); /* if tiny=1, we should compare r with my*2^(ey-ex) */ if (tiny) { if (ex + (mpfr_exp_t) mpz_sizeinbase (r, 2) < ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) compare = 0; /* r*2^ex < my*2^ey */ else { mpz_mul_2exp (my, my, ey - ex); compare = mpz_cmpabs (r, my); } } else compare = mpz_cmpabs (r, my); mpz_fdiv_q_2exp (r, r, 1); compare = ((compare > 0) || ((rnd_q == MPFR_RNDN) && (compare == 0) && q_is_odd)); /* if compare != 0, we need to subtract my to r, and add 1 to quo */ if (compare) { mpz_sub (r, r, my); if (quo && (rnd_q == MPFR_RNDN)) *quo += 1; } } /* take into account sign of x */ if (signx < 0) mpz_neg (r, r); inex = mpfr_set_z_2exp (rem, r, ex > ey ? ey : ex, rnd); } if (quo) *quo *= sign; mpz_clear (mx); mpz_clear (my); mpz_clear (r); return inex; }