cipolla_algorithm_simple.sf 1.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. #!/usr/bin/ruby
  2. # Cipolla's algorithm, for solving a congruence of the form:
  3. # x^2 == n (mod p)
  4. # where p is an odd prime.
  5. # This implementation uses quadratic integers.
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Cipolla's_algorithm
  8. # https://rosettacode.org/wiki/Cipolla%27s_algorithm
  9. func cipolla(n, p) {
  10. kronecker(n, p) == 1 || return nil
  11. var (a, ω) = (
  12. 0..Inf -> lazy.map {|a|
  13. [a, submod(a*a, n, p)]
  14. }.first_by {|t|
  15. kronecker(t[1], p) == -1
  16. }...
  17. )
  18. var r = lift(Mod(Quadratic(a, 1, ω), p)**((p+1)>>1))
  19. r.b == 0 ? r.a : nil
  20. }
  21. var tests = [
  22. [10, 13],
  23. [56, 101],
  24. [8218, 10007],
  25. [8219, 10007],
  26. [331575, 1000003],
  27. [665165880, 1000000007],
  28. [881398088036 1000000000039],
  29. [34035243914635549601583369544560650254325084643201, 10**50 + 151],
  30. ]
  31. for n,p in tests {
  32. var r = cipolla(n, p)
  33. if (defined(r)) {
  34. say "Roots of #{n} are (#{r} #{p-r}) mod #{p}"
  35. } else {
  36. say "No solution for (#{n}, #{p})"
  37. }
  38. }