827 Pythagorean Triple Occurrence -- v2.sf 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #!/usr/bin/ruby
  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. # In Sidef, this is:
  7. # (diff_of_squares(n**2).len - 1) + (sum_of_squares(n**2).len - 1)
  8. func count_of_pythagorean_triples(n) {
  9. # Translation of the PARI/GP program by Michel Marcus, Mar 07 2016.
  10. # https://oeis.org/A046081
  11. var n0_sigma0 = 1
  12. var n1_sigma0 = 1
  13. for p,e in (n.factor_exp) {
  14. if (p == 2) {
  15. n0_sigma0 *= (2*e - 1)
  16. }
  17. else {
  18. n0_sigma0 *= (2*e + 1)
  19. if (p % 4 == 1) {
  20. n1_sigma0 *= (2*e + 1)
  21. }
  22. }
  23. }
  24. (n0_sigma0 + n1_sigma0)/2 - 1
  25. }
  26. func smallest_number_with_n_divisors(threshold, upperbound = false, least_solution = Inf, k = 1, max_a = Inf, max_b = Inf, sol_a = 1, sol_b = 1, n = 1) {
  27. if ((sol_a + sol_b)/2 - 1 == threshold) {
  28. return n
  29. }
  30. if ((sol_a + sol_b)/2 - 1 > threshold) {
  31. return least_solution
  32. }
  33. var p = k.prime
  34. if ((p==2) || (p % 4 == 3)) {
  35. for a in (1 .. max_a) {
  36. n *= p
  37. break if (n > least_solution)
  38. least_solution = __FUNC__(threshold, upperbound, least_solution, k+1, a, (upperbound ? 0 : max_b), sol_a * (p==2 ? (2*a - 1) : (2*a + 1)), sol_b, n)
  39. }
  40. }
  41. else {
  42. for b in (1 .. max_b) {
  43. n *= p
  44. break if (n > least_solution)
  45. least_solution = __FUNC__(threshold, upperbound, least_solution, k+1, (upperbound ? 0 : max_a), b, sol_a * (2*b + 1), sol_b * (2*b + 1), n)
  46. }
  47. }
  48. return least_solution
  49. }
  50. func p827(n) {
  51. var sum = 0
  52. for k in (1..n) {
  53. say "Computing upper-bound for k = #{k}"
  54. var upperbound = smallest_number_with_n_divisors(10**k, true)
  55. say "Upper-bound: #{upperbound}"
  56. var value = smallest_number_with_n_divisors(10**k, false, upperbound)
  57. say "Exact value: #{value}\n"
  58. sum += value
  59. }
  60. return sum
  61. }
  62. say count_of_pythagorean_triples(48)
  63. say count_of_pythagorean_triples(8064000)
  64. assert_eq(
  65. 1000.of(count_of_pythagorean_triples).slice(1),
  66. 1000.of { .sqr.sum_of_squares.len.dec + .sqr.diff_of_squares.len.dec }.slice(1)
  67. )
  68. say p827(18)