678 Fermat-like Equations -- v2.pl 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 25 September 2019
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=678
  6. # Runtime: 53.885s
  7. use 5.020;
  8. use strict;
  9. use warnings;
  10. use experimental qw(signatures);
  11. use ntheory qw(:all);
  12. my %cache;
  13. # All solutions to `n = a^2 + b^2`, with 0 < a <= b
  14. sub sum_of_two_squares_solutions ($n) {
  15. if (exists $cache{$n}) {
  16. return $cache{$n};
  17. }
  18. $n == 0 and return [];
  19. my $prod1 = 1;
  20. my $prod2 = 1;
  21. my @prime_powers;
  22. foreach my $f (factor_exp($n)) {
  23. if ($f->[0] % 4 == 3) { # p = 3 (mod 4)
  24. $f->[1] % 2 == 0 or return []; # power must be even
  25. $prod2 *= powint($f->[0], $f->[1] >> 1);
  26. }
  27. elsif ($f->[0] == 2) { # p = 2
  28. if ($f->[1] % 2 == 0) { # power is even
  29. $prod2 *= powint($f->[0], $f->[1] >> 1);
  30. }
  31. else { # power is odd
  32. $prod1 *= $f->[0];
  33. $prod2 *= powint($f->[0], ($f->[1] - 1) >> 1);
  34. push @prime_powers, [$f->[0], 1];
  35. }
  36. }
  37. else { # p = 1 (mod 4)
  38. $prod1 *= powint($f->[0], $f->[1]);
  39. push @prime_powers, $f;
  40. }
  41. }
  42. $prod1 == 1 and return [];
  43. $prod1 == 2 and return [];
  44. my %table;
  45. foreach my $f (@prime_powers) {
  46. my $pp = powint($f->[0], $f->[1]);
  47. my $r = sqrtmod($pp - 1, $pp);
  48. push @{$table{$pp}}, [$r, $pp], [$pp - $r, $pp];
  49. }
  50. my @square_roots;
  51. forsetproduct {
  52. push @square_roots, chinese(@_);
  53. } values %table;
  54. my @solutions;
  55. foreach my $r (@square_roots) {
  56. my $s = $r;
  57. my $q = $prod1;
  58. while ($s * $s > $prod1) {
  59. ($s, $q) = ($q % $s, $s);
  60. }
  61. push @solutions, [$prod2 * $s, $prod2 * ($q % $s)];
  62. }
  63. foreach my $f (@prime_powers) {
  64. for (my $i = $f->[1] % 2 ; $i < $f->[1] ; $i += 2) {
  65. my $sq = powint($f->[0], ($f->[1] - $i) >> 1);
  66. my $pp = powint($f->[0], $f->[1] - $i);
  67. push @solutions, map {
  68. [map { $sq * $prod2 * $_ } @$_]
  69. } @{sum_of_two_squares_solutions($prod1 / $pp)};
  70. }
  71. }
  72. @solutions = do {
  73. my %seen;
  74. grep { !$seen{$_->[0]}++ } map {
  75. [sort { $a <=> $b } @$_]
  76. } @solutions;
  77. };
  78. return ($cache{$n} = \@solutions);
  79. }
  80. # Number of solutions to `n = a^2 + b^2, with 0 < a < b.
  81. # OEIS: https://oeis.org/A025441
  82. sub r2_squares ($n) {
  83. my $B = 1;
  84. foreach my $p (factor_exp($n)) {
  85. my $r = $p->[0] % 4;
  86. if ($r == 3) {
  87. $p->[1] % 2 == 0 or return 0;
  88. }
  89. if ($r == 1) {
  90. $B *= $p->[1] + 1;
  91. }
  92. }
  93. return ($B >> 1);
  94. }
  95. # Number of solutions to `n = a^3 + b^3, with 0 < a < b.
  96. # OEIS: https://oeis.org/A025468
  97. sub r2_cubes ($n) {
  98. my $count = 0;
  99. foreach my $d (divisors($n)) {
  100. my $l = $d * $d - $n / $d;
  101. ($l % 3 == 0) || next;
  102. my $t = $d * $d - 4 * ($l / 3);
  103. if ($d * $d * $d >= $n and $d * $d * $d <= 4 * $n and $l >= 3 and $t > 0 and is_square($t)) {
  104. ++$count;
  105. }
  106. }
  107. return $count;
  108. }
  109. # Number of solutions to `n = (a^2)^2 + (b^2)^2, with 0 < a < b.
  110. sub r2_fourth_powers ($n) {
  111. scalar grep { $_->[0] > 0 and $_->[1] > 0 and $_->[0] != $_->[1] and is_square($_->[0]) and is_square($_->[1]) }
  112. @{sum_of_two_squares_solutions($n)};
  113. }
  114. # Count the number of representations as sums of two squares.
  115. sub count_sum_of_squares ($N) {
  116. say ":: First stage...";
  117. my $count = 0;
  118. foreach my $f (3 .. logint($N, 2)) {
  119. foreach my $c (2 .. rootint($N, $f)) {
  120. $count += r2_squares(powint($c, $f));
  121. }
  122. }
  123. say ":: There are $count solutions to `n^k = a^2 + b^2`, with k >= 3.";
  124. return $count;
  125. }
  126. # Count the number of representations as sums of two cubes (faster solution).
  127. sub count_sum_of_cubes ($N) {
  128. say ":: Second stage...";
  129. my $count = 0;
  130. foreach my $f (4 .. logint($N, 2)) {
  131. foreach my $c (2 .. rootint($N, $f)) {
  132. $count += r2_cubes(powint($c, $f));
  133. }
  134. }
  135. say ":: There are $count solutions to `n^k = a^3 + b^3`, with k >= 4.";
  136. return $count;
  137. }
  138. sub count_sum_of_fourth_powers ($N) {
  139. say ":: Third stage...";
  140. my $count = 0;
  141. foreach my $f (3, 5 .. logint($N, 2)) {
  142. foreach my $c (2 .. rootint($N, $f)) {
  143. $count += r2_fourth_powers(powint($c, $f));
  144. }
  145. }
  146. say ":: There are $count solutions to `n^k = a^4 + b^4`, with k >= 3.";
  147. return $count;
  148. }
  149. # Count the number of representations as sums of powers a^e with e >= 5.
  150. sub count_other_powers ($N) {
  151. say ":: Fourth stage...";
  152. my $count = 0;
  153. foreach my $u (1 .. rootint($N >> 1, 5)) {
  154. foreach my $v ($u + 1 .. $N) {
  155. my $x = $u * $u * $u * $u * $u;
  156. my $y = $v * $v * $v * $v * $v;
  157. last if ($x + $y > $N);
  158. while ($x + $y <= $N) {
  159. my $pow = is_power($x + $y);
  160. if ($pow > 2) {
  161. $count += divisor_sum($pow, 0) - ($pow % 2 == 0) - 1;
  162. }
  163. $x *= $u;
  164. $y *= $v;
  165. }
  166. }
  167. }
  168. say ":: There are $count solutions to `n^k = a^e + b^e`, with k >= 3 and e >= 5";
  169. return $count;
  170. }
  171. sub F ($N) {
  172. my $x = count_sum_of_squares($N);
  173. my $y = count_sum_of_cubes($N);
  174. my $f = count_sum_of_fourth_powers($N);
  175. my $z = count_other_powers($N);
  176. my $total = $x + $y + $z + $f;
  177. return $total;
  178. }
  179. say F(powint(10, 18));
  180. __END__
  181. # F(10^10) = 3231
  182. # F(10^11) = 7212
  183. # F(10^12) = 16066
  184. # F(10^13) = 35816
  185. # F(10^14) = 80056
  186. # F(10^15) = 178578
  187. ## For n^k <= 10^18:
  188. :: There are 1985353 solutions to `n^k = a^2 + b^2`, with k >= 3.
  189. :: There are 669 solutions to `n^k = a^3 + b^3`, with k >= 4.
  190. :: There are 30 solutions to `n^k = a^4 + b^4`, with k >= 3.
  191. :: There are 13 solutions to `n^k = a^e + b^e`, with k >= 3 and e >= 5