sophie_germain_factorization_method.sf 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 26 July 2019
  4. # https://github.com/trizen
  5. # A simple factorization method, based on Sophie Germain's identity:
  6. # x^4 + 4y^4 = (x^2 + 2xy + 2y^2) * (x^2 - 2xy + 2y^2)
  7. # This method is also effective for numbers of the form: n^4 + 4^(2k+1).
  8. # See also:
  9. # https://oeis.org/A227855 -- Numbers of the form x^4 + 4*y^4.
  10. # https://www.quora.com/What-is-Sophie-Germains-Identity
  11. func sophie_germain_factorization (n) {
  12. func sophie(A, B) {
  13. var factors = []
  14. for f in (
  15. A**2 + 2*B*B - 2*A*B,
  16. A**2 + 2*B*B + 2*A*B,
  17. ) {
  18. var g = gcd(f, n)
  19. if (g.is_between(2, n-1)) {
  20. while (n%g == 0) {
  21. n /= g
  22. factors << g
  23. }
  24. }
  25. }
  26. factors
  27. }
  28. var orig = n
  29. var sophie_params = []
  30. func sophie_check_root(r1) {
  31. var x = (4 * r1**4)
  32. var dx = (n - x)
  33. if (dx.is_power(4)) {
  34. var r2 = dx.iroot(4)
  35. sophie_params << [r2, r1]
  36. }
  37. var y = (r1**4)
  38. var dy = (n - y)
  39. if ((dy%4 == 0) && (dy/4).is_power(4)) {
  40. var r2 = (dy/4).iroot(4)
  41. sophie_params << [r1, r2]
  42. }
  43. }
  44. # Try to find n = x^4 + 4*y^4, for x or y small.
  45. for r in (2..n.ilog2) {
  46. sophie_check_root(r)
  47. }
  48. # Try to find n = x^4 + 4*y^4 for x,y close to floor(n/5)^(1/4).
  49. var k = floor(n/5).iroot(4)
  50. for j in (0..100) {
  51. sophie_check_root(k + j)
  52. }
  53. var factors = []
  54. for args in (sophie_params) {
  55. factors << sophie(args...)...
  56. }
  57. factors << orig/factors.prod
  58. factors.sort
  59. }
  60. if (ARGV) {
  61. say sophie_germain_factorization(Num(ARGV[0]))
  62. return 1
  63. }
  64. say sophie_germain_factorization(ipow(43, 4) + 4*ipow(372485613, 4)) #=> [277491031750210669, 277491095817736105]
  65. say sophie_germain_factorization(ipow(372485613, 4) + 4*ipow(97, 4)) #=> [138745459629795665, 138745604154213509]
  66. say sophie_germain_factorization(ipow(372485613, 4) + 4*ipow(372485629, 4)) #=> [138745543811525897, 693727695218548205]
  67. say sophie_germain_factorization(ipow(372485629, 4) + 4*ipow(372485511, 4)) #=> [138745455904945045, 693727455337830721]
  68. say '';
  69. say sophie_germain_factorization(ipow(4, 117) + ipow(53, 4)) #=> [166153499473114453560556010453601017, 166153499473114514665395754616490745]
  70. say sophie_germain_factorization(ipow(4, 213) + ipow(240, 4)) #=> [13164036458569648337239753460419861813422875717854660184319779072, 13164036458569648337239753460497746266300898132282617629258080512]
  71. say sophie_germain_factorization(ipow(4, 251) + ipow(251, 4)) #=> [3618502788666131106986593281521497099061968496512379043906292883903830095385, 3618502788666131106986593281521497141767405545090156208559806116590740633113]