linear_diophantine_equation_invmod_search.sf 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/ruby
  2. # Find the smallest solution in positive integers to the equation:
  3. #
  4. # a*x - b*y = n
  5. #
  6. # where a,b,n are given and n is an intermediate value in Euclid's GCD(a,b) algorithm.
  7. # See also:
  8. # https://en.wikipedia.org/wiki/Diophantine_equation
  9. # https://mathworld.wolfram.com/DiophantineEquation.html
  10. func modular_inverse_search (a, n, z) {
  11. var (u, w) = (1, 0)
  12. var (q, r) = (0, 0)
  13. var c = n
  14. while (c != 0) {
  15. (q, r) = divmod(a, c)
  16. (a, c) = (c, r)
  17. (u, w) = (w, u - q*w)
  18. break if (a == z)
  19. }
  20. u += n if (u < 0)
  21. return u
  22. }
  23. func solve(a, b, c) {
  24. var x = modular_inverse_search(a, b, c)
  25. var y = ((a*x - c) / b)
  26. return (x, y)
  27. }
  28. var tests = [
  29. [79, 23, 1],
  30. [97, 43, 1],
  31. [43, 97, 1],
  32. [55, 28, 1],
  33. [42, 22, 2],
  34. [79, 23, 10],
  35. ]
  36. for a,b,n in tests {
  37. var (x, y) = solve(a, b, n)
  38. assert(x.is_int)
  39. assert(b.is_int)
  40. assert_eq(a*x - b*y, n)
  41. printf("#{a}*x - #{b}*y = %2s --> (x, y) = (%2s, %2s)\n", n, x, y)
  42. }
  43. say "\n>> Extra tests:"
  44. var a = 43*97
  45. var b = 41*57
  46. for n in ([1, 7, 8, 23, 31, 147, 178, 325, 503, 1834]) {
  47. var (x, y) = solve(a, b, n)
  48. assert(x.is_int)
  49. assert(y.is_int)
  50. assert_eq(a*x - b*y, n)
  51. printf("#{a}*x - #{b}*y = %4s --> (x, y) = (%5s, %5s)\n", n, x, y)
  52. }
  53. __END__
  54. 79*x - 23*y = 1 --> (x, y) = ( 7, 24)
  55. 97*x - 43*y = 1 --> (x, y) = ( 4, 9)
  56. 43*x - 97*y = 1 --> (x, y) = (88, 39)
  57. 55*x - 28*y = 1 --> (x, y) = (27, 53)
  58. 42*x - 22*y = 2 --> (x, y) = (21, 40)
  59. 79*x - 23*y = 10 --> (x, y) = ( 1, 3)
  60. >> Extra tests:
  61. 4171*x - 2337*y = 1 --> (x, y) = ( 2035, 3632)
  62. 4171*x - 2337*y = 7 --> (x, y) = ( 223, 398)
  63. 4171*x - 2337*y = 8 --> (x, y) = ( 2258, 4030)
  64. 4171*x - 2337*y = 23 --> (x, y) = ( 65, 116)
  65. 4171*x - 2337*y = 31 --> (x, y) = ( 2323, 4146)
  66. 4171*x - 2337*y = 147 --> (x, y) = ( 9, 16)
  67. 4171*x - 2337*y = 178 --> (x, y) = ( 2332, 4162)
  68. 4171*x - 2337*y = 325 --> (x, y) = ( 4, 7)
  69. 4171*x - 2337*y = 503 --> (x, y) = ( 2336, 4169)
  70. 4171*x - 2337*y = 1834 --> (x, y) = ( 1, 1)