7 #include "cl_numtheory.h"
14 // [Cohen], section 1.5.2, algorithm 1.5.3.
15 // For proofs refer to [F. Morain, J.-L. Nicolas: On Cornacchia's algorithm
16 // for solving the diophantine equation u^2+v*d^2=m].
18 const cornacchia_t cornacchia4 (const cl_I& d, const cl_I& p)
21 // Goal: Solve x^2+d*y^2 = 4*p.
22 // If p=2: {0,1,4,...} + d*{0,1,4,...} = 8.
23 // d=1: (x,y) = (2,2).
24 // d=2: (x,y) = (0,2).
25 // d=4: (x,y) = (2,1).
26 // d=7: (x,y) = (1,1).
30 // x must be even. Solve u^2 + (d/4)*y^2 = p, return (2*u,y).
32 // x must be even, then y must be even. Solve u^2 + d*v^2 = p,
34 // If d == 1,5,7 mod 8:
35 // x^2+d*y^2 == 4 mod 8, x^2 and y^2 can only be == 0,1,4 mod 8.
36 // x and y must be even. Solve u^2 + d*v^2 = p, return (2*u,2*v).
38 // Compute x with x^2+d == 0 mod 4*p.
39 // Euclidean algorithm on a = 2*p, b = x, stop when a remainder
40 // <= 2*sqrt(p) has been reached.
45 return cornacchia_t(1, 0,1);
47 // d > 4*p -> no solution
48 return cornacchia_t(0);
52 if (d==1) return cornacchia_t(1, 2,2);
53 if (d==2) return cornacchia_t(1, 0,2);
54 if (d==4) return cornacchia_t(1, 2,1);
55 if (d==7) return cornacchia_t(1, 1,1);
56 return cornacchia_t(0);
58 switch (FN_to_L(logand(d,7))) {
61 var cornacchia_t s = cornacchia1(d>>2,p);
64 s.solution_x = s.solution_x<<1;
67 case 1: case 2: case 5: case 6: case 7: {
68 var cornacchia_t s = cornacchia1(d,p);
70 if (s.solutions != 0) {
71 s.solution_x = s.solution_x<<1;
72 s.solution_y = s.solution_y<<1;
79 switch (jacobi(-d,p)) {
80 case -1: // no solution
81 return cornacchia_t(0);
82 case 0: // gcd(d,p) > 1
83 return new cl_composite_condition(p,gcd(d,p));
87 // Compute x with x^2+d == 0 mod p.
88 var cl_modint_ring R = cl_find_modint_ring(p);
89 var sqrt_mod_p_t init = sqrt_mod_p(R,R->canonhom(-d));
91 return init.condition;
92 if (init.solutions != 2)
94 // Compute x with x^2+d == 0 mod 4*p.
95 var cl_I x0 = R->retract(init.solution[0]);
96 if (evenp(x0)) { x0 = p-x0; } // Enforce x0^2+d == 0 mod 4.
97 // Euclidean algorithm.
100 var cl_I limit = isqrt(p4);
102 var cl_I r = mod(a,b);
105 // b is the first euclidean remainder <= 2*sqrt(p).
107 var cl_I_div_t div = floor2(p4-square(b),d);
108 if (!zerop(div.remainder))
109 return cornacchia_t(0);
110 var cl_I& c = div.quotient;
113 return cornacchia_t(0);
114 return cornacchia_t(1, x,y);