difference_of_powers_factorization_method.sf 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 04 July 2019
  4. # Edit: 28 July 2019
  5. # https://github.com/trizen
  6. # A simple factorization method for numbers that can be expressed as a difference of powers.
  7. # Very effective for numbers of the form:
  8. #
  9. # n^k - 1
  10. #
  11. # where k has many divisors.
  12. # See also:
  13. # https://trizenx.blogspot.com/2019/08/special-purpose-factorization-algorithms.html
  14. define MIN_FACTOR = 1e6 # ignore small factors
  15. func diff_power_factorization (n) {
  16. var orig = n
  17. var params = []
  18. func f(r1, e1, r2, e2) {
  19. var factors = Set()
  20. var divs1 = divisors(e1)
  21. var divs2 = divisors(e2)
  22. for d1 in (divs1), d2 in (divs2), j in (1, -1) {
  23. var t = (powmod(r1, d1, n) - (j * r2**d2))
  24. var g = gcd(t, n)
  25. if (g>MIN_FACTOR && g<n) {
  26. factors << g
  27. }
  28. }
  29. factors.to_a
  30. }
  31. func check_power (r1, e1) {
  32. var u = r1**e1
  33. var dx = abs(u - n)
  34. if (dx.is_power) {
  35. var e2 = dx.perfect_power
  36. var r2 = dx.perfect_root
  37. params << [r1, e1, r2, e2]
  38. }
  39. }
  40. for r1 in (2 .. n.ilog2) {
  41. var t = n.ilog(r1)
  42. check_power(r1, t)
  43. check_power(r1, t+1)
  44. }
  45. for e1 in (2 .. n.ilog2) {
  46. var t = n.iroot(e1)
  47. check_power(t, e1)
  48. check_power(t+1, e1)
  49. }
  50. var factors = []
  51. var divisors = params.uniq.map { f(_...) }.flat.sort.uniq
  52. divisors.each {|d|
  53. var g = gcd(n, d)
  54. if (g>MIN_FACTOR && g<n) {
  55. while (g `divides` n) {
  56. n /= g
  57. factors << g
  58. }
  59. }
  60. }
  61. factors << (orig / factors.prod)
  62. factors.sort
  63. }
  64. if (ARGV) {
  65. say diff_power_factorization(Num(ARGV[0]))
  66. return 1
  67. }
  68. say diff_power_factorization(1009**24 + 29**12)
  69. say diff_power_factorization(1009**24 - 29**12)
  70. say diff_power_factorization(2**256 - 1)
  71. say diff_power_factorization(10**120 + 1)
  72. say diff_power_factorization(10**120 - 1)
  73. say diff_power_factorization(10**120 - 25)
  74. say diff_power_factorization(10**105 - 1)
  75. say diff_power_factorization(10**105 + 1)
  76. say diff_power_factorization(10**120 - 2134**2)
  77. __END__
  78. [1074309286591662655506002, 1154140443257087164049583013000044736320575461201]
  79. [1018052, 1018110, 1036459399053, 1036488923402, 1036518447751, 1074309285719975471632201]
  80. [4294967295, 4294967297, 18446744073709551617, 340282366920938463463374607431768211457]
  81. [100000001, 9999999900000001, 99999999000000009999999900000001, 10000000099999999999999989999999899999999000000000000000100000001]
  82. [1000001, 99009901, 9999900001, 9999999999, 10000100001, 1000000000001, 9999000099990001, 10099989899000101, 100009999999899989999000000010001]
  83. [999999999999999999999999999999999999999999999999999999999995, 1000000000000000000000000000000000000000000000000000000000005]
  84. [9999999, 900900990991, 111111111111111, 900009090090909909099991, 1109988789001111109989898989900111110998878900111]
  85. [10000001, 1098900989011, 90909090909091, 1099988890111109888900011, 910009191000909089989898989899909091000919100091]
  86. [999999999999999999999999999999999999999999999999999999997866, 1000000000000000000000000000000000000000000000000000000002134]