private Diophantine Chakravala(Diophantine d, long N) { // see aforementioned wikipedia page for how this works. Essentially if you have two solutions to a more general // a^2 - N*b^2 = k, you can compose the two solutions to find yet another. Eventually k == 1 and you have // the solution we are looking for. while (d.k != 1) { BigInteger m, a, b, k; if (d.k == -1) { //special case, compose d with itself a = (d.a * d.a + N * d.b * d.b); b = (2 * d.a * d.b); k = 1; } else { m = ChooseM(d, N); a = (d.a * m + N * d.b) / BigInteger.Abs(d.k); b = (d.a + d.b * m) / BigInteger.Abs(d.k); k = (m * m - N) / d.k; } d.a = a; d.b = b; d.k = k; } return(d); }
private BigInteger ChooseM(Diophantine d, long N) { // we need m such that k | (a + bm) that minimizes (m^2 - N) // first find possible m // a + bm = 0 mod k // => m = -a(b^-1) mod k var sqrtN = (int)Math.Sqrt(N); var k = BigInteger.Abs(d.k); var invB = Modular.ModularMultiplicativeInverse(d.b, k); // apparently gcd(b, k) = 1 always, so this is legit ¯\_(ツ)_/¯ var m = (-d.a) * invB; var m0 = m + ((sqrtN - m) / k) * k; var m1 = m + ((sqrtN - m) / k + 1) * k; return(new[] { m0, m1 }.OrderBy(x => BigInteger.Abs(x * x - N)).First()); }
public static void diophantine_solution_minimize_test() //****************************************************************************80 // // Purpose: // // DIOPHANTINE_SOLUTION_MINIMIZE_TEST tests DIOPHANTINE_SOLUTION_MINIMIZE. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 02 December 2006 // // Author: // // John Burkardt // { const int a = 4096; const int b = -15625; const int c = 46116; Console.WriteLine(""); Console.WriteLine("DIOPHANTINE_SOLUTION_MINIMIZE_TEST"); Console.WriteLine(" DIOPHANTINE_SOLUTION_MINIMIZE computes a minimal"); Console.WriteLine(" Euclidean norm solution of a Diophantine equation:"); Console.WriteLine(" A * X + B * Y = C"); int x = 665499996; int y = 174456828; int r = a * x + b * y - c; Console.WriteLine(""); Console.WriteLine(" Coefficients:"); Console.WriteLine(" A = " + a.ToString().PadLeft(12) + ""); Console.WriteLine(" B = " + b.ToString().PadLeft(12) + ""); Console.WriteLine(" C = " + c.ToString().PadLeft(12) + ""); Console.WriteLine(" Solution:"); Console.WriteLine(" X = " + x.ToString().PadLeft(12) + ""); Console.WriteLine(" Y = " + y.ToString().PadLeft(12) + ""); Console.WriteLine(" Residual R = A * X + B * Y - C:"); Console.WriteLine(" R = " + r.ToString().PadLeft(12) + ""); Diophantine.diophantine_solution_minimize(a, b, ref x, ref y); r = a * x + b * y - c; Console.WriteLine(""); Console.WriteLine(" DIOPHANTINE_SOLUTION_MINIMIZE returns"); Console.WriteLine(" the minimized solution:"); Console.WriteLine(" X = " + x.ToString().PadLeft(12) + ""); Console.WriteLine(" Y = " + y.ToString().PadLeft(12) + ""); Console.WriteLine(" Residual R = A * X + B * Y - C:"); Console.WriteLine(" R = " + r.ToString().PadLeft(12) + ""); x = 15621; y = 4092; r = a * x + b * y - c; Console.WriteLine(""); Console.WriteLine(" Here is the minimal positive solution:"); Console.WriteLine(" X = " + x.ToString().PadLeft(12) + ""); Console.WriteLine(" Y = " + y.ToString().PadLeft(12) + ""); Console.WriteLine(" Residual R = A * X + B * Y - C:"); Console.WriteLine(" R = " + r.ToString().PadLeft(12) + ""); }
public static void diophantine_test() //****************************************************************************80 // // Purpose: // // DIOPHANTINE_TEST tests DIOPHANTINE. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 02 December 2006 // // Author: // // John Burkardt // { const int TEST_NUM = 20; int[] a_test = { 1027, 1027, 1027, 1027, -1027, -1027, -1027, -1027, 6, 0, 0, 0, 1, 1, 1, 1024, 0, 0, 5, 2 }; int[] b_test = { 712, 712, -712, -712, 712, 712, -712, -712, 8, 0, 1, 1, 0, 0, 1, -15625, 0, 3, 0, 4 }; int[] c_test = { 7, -7, 7, -7, 7, -7, 7, -7, 50, 0, 0, 1, 0, 1, 0, 11529, 1, 11, 19, 7 }; bool error = false; int test_i; int x = 0; int y = 0; Console.WriteLine(""); Console.WriteLine("DIOPHANTINE_TEST"); Console.WriteLine(" DIOPHANTINE solves a Diophantine equation:"); Console.WriteLine(" A * X + B * Y = C"); Console.WriteLine(""); Console.WriteLine(" A B C X Y Residual"); Console.WriteLine(""); for (test_i = 0; test_i < TEST_NUM; test_i++) { int a = a_test[test_i]; int b = b_test[test_i]; int c = c_test[test_i]; Diophantine.diophantine(a, b, c, ref error, ref x, ref y); switch (error) { case true: Console.WriteLine(a.ToString().PadLeft(10) + " " + b.ToString().PadLeft(10) + " " + c.ToString().PadLeft(10) + " " + "(Error occurred!)" + ""); break; default: int r = a * x + b * y - c; Console.WriteLine(a.ToString().PadLeft(10) + " " + b.ToString().PadLeft(10) + " " + c.ToString().PadLeft(10) + " " + x.ToString().PadLeft(10) + " " + y.ToString().PadLeft(10) + " " + r.ToString().PadLeft(10) + ""); break; } } }