sum_of_two_squares_multiple_solutions.pl 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 24 October 2017
  4. # https://github.com/trizen
  5. # Algorithm for finding solutions to the equation a^2 + b^2 = n,
  6. # for any given positive integer `n` for which such a solution exists.
  7. # The number of returned solutions is at least as many as
  8. # the number of unique prime factors p = 1 (mod 4) in `n`.
  9. # For numbers with primes powers p^k = 1 (mod 4), for k > 1, not all the possible solutions are returned.
  10. # For example, when n = 9925 = 5^2 * 397, only the following two solutions are returned: [58, 81], [33, 94].
  11. # The missing solution for 9925, is: [30, 95].
  12. # This algorithm is efficient when the factorization of `n` is known.
  13. # See also:
  14. # https://oeis.org/A001481
  15. use 5.020;
  16. use strict;
  17. use warnings;
  18. use experimental qw(signatures);
  19. use ntheory qw(sqrtmod factor_exp chinese forsetproduct);
  20. sub sum_of_two_squares_solution ($n) {
  21. $n == 0 and return [0, 0];
  22. my $prod1 = 1;
  23. my $prod2 = 1;
  24. my @prime_powers;
  25. foreach my $f (factor_exp($n)) {
  26. if ($f->[0] % 4 == 3) { # p = 3 (mod 4)
  27. $f->[1] % 2 == 0 or return; # power must be even
  28. $prod2 *= $f->[0]**($f->[1] >> 1);
  29. }
  30. elsif ($f->[0] == 2) { # p = 2
  31. if ($f->[1] % 2 == 0) { # power is even
  32. $prod2 *= $f->[0]**($f->[1] >> 1);
  33. }
  34. else { # power is odd
  35. $prod1 *= $f->[0];
  36. $prod2 *= $f->[0]**(($f->[1] - 1) >> 1);
  37. push @prime_powers, $f->[0];
  38. }
  39. }
  40. else { # p = 1 (mod 4)
  41. $prod1 *= $f->[0]**$f->[1];
  42. push @prime_powers, $f->[0]**$f->[1];
  43. }
  44. }
  45. $prod1 == 1 and return [$prod2, 0];
  46. $prod1 == 2 and return [$prod2, $prod2];
  47. my %table;
  48. foreach my $pp (@prime_powers) {
  49. my $r = sqrtmod($pp - 1, $pp);
  50. push @{$table{$pp}}, [$r, $pp], [$pp - $r, $pp];
  51. }
  52. my @square_roots;
  53. forsetproduct {
  54. push @square_roots, chinese(@_);
  55. } values %table;
  56. my @solutions;
  57. foreach my $r (@square_roots) {
  58. my $s = $r;
  59. my $q = $prod1;
  60. while ($s * $s > $prod1) {
  61. ($s, $q) = ($q % $s, $s);
  62. }
  63. push @solutions, [$prod2 * $s, $prod2 * ($q % $s)];
  64. }
  65. return sort { $a->[0] <=> $b->[0] } do {
  66. my %seen;
  67. grep { !$seen{$_->[0]}++ } map {
  68. [sort { $a <=> $b } @$_]
  69. } @solutions;
  70. };
  71. }
  72. foreach my $n (1 .. 1e5) {
  73. (my @solutions = sum_of_two_squares_solution($n)) || next;
  74. say "$n = " . join(' = ', map { "$_->[0]^2 + $_->[1]^2" } @solutions);
  75. # Verify solutions
  76. foreach my $solution (@solutions) {
  77. if ($n != $solution->[0]**2 + $solution->[1]**2) {
  78. die "error for $n: (@$solution)\n";
  79. }
  80. }
  81. }
  82. __END__
  83. 999826 = 99^2 + 995^2 = 315^2 + 949^2 = 699^2 + 715^2 = 525^2 + 851^2
  84. 999828 = 318^2 + 948^2
  85. 999844 = 410^2 + 912^2 = 312^2 + 950^2
  86. 999848 = 62^2 + 998^2
  87. 999850 = 43^2 + 999^2 = 321^2 + 947^2
  88. 999853 = 387^2 + 922^2
  89. 999857 = 544^2 + 839^2 = 401^2 + 916^2
  90. 999860 = 698^2 + 716^2 = 154^2 + 988^2
  91. 999869 = 262^2 + 965^2 = 613^2 + 790^2
  92. 999881 = 484^2 + 875^2 = 341^2 + 940^2
  93. 999882 = 309^2 + 951^2 = 651^2 + 759^2
  94. 999890 = 421^2 + 907^2 = 473^2 + 881^2
  95. 999892 = 324^2 + 946^2
  96. 999898 = 697^2 + 717^2 = 213^2 + 977^2
  97. 999909 = 678^2 + 735^2 = 222^2 + 975^2
  98. 999914 = 667^2 + 745^2
  99. 999917 = 109^2 + 994^2
  100. 999937 = 89^2 + 996^2 = 44^2 + 999^2
  101. 999938 = 77^2 + 997^2
  102. 999940 = 696^2 + 718^2 = 126^2 + 992^2 = 448^2 + 894^2 = 178^2 + 984^2
  103. 999941 = 446^2 + 895^2 = 370^2 + 929^2
  104. 999944 = 638^2 + 770^2
  105. 999946 = 585^2 + 811^2
  106. 999949 = 243^2 + 970^2 = 450^2 + 893^2
  107. 999952 = 444^2 + 896^2
  108. 999953 = 568^2 + 823^2
  109. 999954 = 375^2 + 927^2 = 327^2 + 945^2
  110. 999956 = 500^2 + 866^2
  111. 999961 = 644^2 + 765^2
  112. 999962 = 541^2 + 841^2 = 239^2 + 971^2
  113. 999968 = 452^2 + 892^2
  114. 999970 = 627^2 + 779^2 = 247^2 + 969^2
  115. 999973 = 658^2 + 753^2 = 118^2 + 993^2 = 63^2 + 998^2 = 622^2 + 783^2
  116. 999981 = 141^2 + 990^2
  117. 999986 = 365^2 + 931^2 = 695^2 + 719^2
  118. 999997 = 194^2 + 981^2 = 454^2 + 891^2
  119. 1000000 = 352^2 + 936^2