827 Pythagorean Triple Occurrence.pl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #!/usr/bin/perl
  2. # Pythagorean Triple Occurrence
  3. # https://projecteuler.net/problem=827
  4. # For a given number n, the number of Pythagorean triples in which the number n occurs, is equivalent with:
  5. # (number of solutions to x^2 - y^2 = n^2, with x,y > 0) + (number of solutions to x^2 + y^2 = n^2, with x,y > 0).
  6. use 5.020;
  7. use strict;
  8. use warnings;
  9. use ntheory qw(:all);
  10. use experimental qw(signatures);
  11. use Math::GMPz;
  12. sub count_of_pythagorean_triples ($n) {
  13. # Translation of the PARI/GP program by Michel Marcus, Mar 07 2016.
  14. # https://oeis.org/A046081
  15. my $n0_sigma0 = 1;
  16. my $n1_sigma0 = 1;
  17. foreach my $pp (factor_exp($n)) {
  18. my ($p, $e) = @$pp;
  19. if ($p == 2) {
  20. $n0_sigma0 *= (2 * $e - 1);
  21. }
  22. else {
  23. $n0_sigma0 *= (2 * $e + 1);
  24. if ($p % 4 == 1) {
  25. $n1_sigma0 *= (2 * $e + 1);
  26. }
  27. }
  28. }
  29. divint(addint($n0_sigma0, $n1_sigma0), 2) - 1;
  30. }
  31. sub smallest_number_with_n_divisors (
  32. $threshold,
  33. $upperbound = 0,
  34. $least_solution = 'inf',
  35. $k = 1,
  36. $max_a = 'inf',
  37. $max_b = 'inf',
  38. $sol_a = 1,
  39. $sol_b = 1,
  40. $n = Math::GMPz->new(1)
  41. ) {
  42. if ((($sol_a + $sol_b) >> 1) - 1 == $threshold) {
  43. return $n;
  44. }
  45. if ((($sol_a + $sol_b) >> 1) - 1 > $threshold) {
  46. return $least_solution;
  47. }
  48. my $p = nth_prime($k);
  49. if ($p == 2 or $p % 4 == 3) {
  50. for (my $e = 1 ; $e <= $max_a ; ++$e) {
  51. $n *= $p;
  52. last if ($n > $least_solution);
  53. $least_solution =
  54. __SUB__->(
  55. $threshold, $upperbound, $least_solution, $k + 1, $e,
  56. ($upperbound ? 0 : $max_b),
  57. $sol_a * ($p == 2 ? (2 * $e - 1) : (2 * $e + 1)),
  58. $sol_b, $n
  59. );
  60. }
  61. }
  62. else {
  63. for (my $e = 1 ; $e <= $max_b ; ++$e) {
  64. $n *= $p;
  65. last if ($n > $least_solution);
  66. $least_solution =
  67. __SUB__->(
  68. $threshold, $upperbound, $least_solution, $k + 1, ($upperbound ? 0 : $max_a),
  69. $e,
  70. $sol_a * (2 * $e + 1),
  71. $sol_b * (2 * $e + 1), $n
  72. );
  73. }
  74. }
  75. return $least_solution;
  76. }
  77. sub p827 ($n) {
  78. my $sum = 0;
  79. foreach my $k (1 .. $n) {
  80. say "Computing upper-bound for k = $k";
  81. my $upperbound = smallest_number_with_n_divisors(powint(10, $k), 1);
  82. say "Upper-bound: $upperbound";
  83. my $value = smallest_number_with_n_divisors(powint(10, $k), 0, $upperbound);
  84. say "Exact value: $value\n";
  85. $sum = addmod($sum, $value, 409120391);
  86. }
  87. return $sum;
  88. }
  89. count_of_pythagorean_triples(48) == 10 or die "error";
  90. count_of_pythagorean_triples(8064000) == 1000 or die "error";
  91. say p827(18);
  92. __END__
  93. Computing upper-bound for k = 1
  94. Upper-bound: 48
  95. Exact value: 48
  96. Computing upper-bound for k = 2
  97. Upper-bound: 51539607552
  98. Exact value: 51539607552
  99. Computing upper-bound for k = 3
  100. Upper-bound: 279936000
  101. Exact value: 8064000
  102. Computing upper-bound for k = 4
  103. Upper-bound: 323936494694900741443154768834215373577729211317092352
  104. Exact value: 352039933204650878906250000000
  105. Computing upper-bound for k = 5
  106. Upper-bound: 1216423776811610842465814209161697337224368319788498338966103771825434751935052774229283362057403149142800669446206368901298211803369795583729399752920557463200093691707392
  107. Exact value: 1216423776811610842465814209161697337224368319788498338966103771825434751935052774229283362057403149142800669446206368901298211803369795583729399752920557463200093691707392