solution.scm 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. ;; https://projecteuler.net/problem=27
  2. ;; Quadratic primes
  3. ;; Problem 27
  4. ;; Euler discovered the remarkable quadratic formula:
  5. ;; n^2 + n + 41
  6. ;; It turns out that the formula will produce 40 primes for
  7. ;; the consecutive integer values
  8. ;; 0 <= n <= 39
  9. ;; . However, when
  10. ;; n = 40
  11. ;; 40^2 + 40 + 41 = 40(40 + 1) + 41
  12. ;; is divisible by 41, and certainly when
  13. ;; n = 41
  14. ;; 41^2 + 41 + 41
  15. ;; is clearly divisible by 41.
  16. ;; The incredible formula
  17. ;; n^2 - 79n + 1601
  18. ;; was discovered, which produces 80 primes for the
  19. ;; consecutive values
  20. ;; 0 <= n <= 79
  21. ;; . The product of the coefficients, -79 and 1601, is
  22. ;; -126479.
  23. ;; Considering quadratics of the form:
  24. ;; n^2 + an + b, where |a| < 1000 and |b| <= 1000
  25. ;; where |n| is the modulus/absolute value of n
  26. ;; e.g. |11| = 11 and |-4| = 4
  27. ;; Find the product of the coefficients, a and b, for the
  28. ;; quadratic expression that produces the maximum number of
  29. ;; primes for consecutive values of n, starting with n = 0.
  30. (import
  31. (except (rnrs base) let-values map)
  32. (only (guile)
  33. lambda* λ)
  34. (ice-9 match)
  35. (contract)
  36. (prefix (lib math) math:)
  37. (lib naive-prime-test)
  38. (lib print-utils)
  39. (lib parallelism)
  40. (lib segment))
  41. (define make-quadratic-formula
  42. (λ (coeff-a coeff-b)
  43. ;; (when (and (= coeff-a -61) (= coeff-b 971))
  44. ;; (print "making quadratic formula with a =" coeff-a "and b =" coeff-b))
  45. (λ (num)
  46. (+ (math:square num)
  47. (* coeff-a num)
  48. coeff-b))))
  49. ;; (define-with-contract euler-remarkable-formula
  50. ;; (require (integer? num)
  51. ;; (and (>= num 0) (< num 40)))
  52. ;; (ensure (integer? <?>)
  53. ;; (positive? <?>)
  54. ;; (prime? <?>))
  55. ;; (λ (num)
  56. ;; ((make-quadratic-formula 1 41) num)))
  57. ;; (define-with-contract incredible-formula
  58. ;; (require (integer? num)
  59. ;; (and (>= num 0) (< num 80)))
  60. ;; (ensure (integer? <?>)
  61. ;; (positive? <?>)
  62. ;; (prime? <?>))
  63. ;; (λ (num)
  64. ;; ((make-quadratic-formula -79 1601) num)))
  65. (define-with-contract number-of-primes
  66. (require (procedure? formula))
  67. (ensure (math:natural-number? <?>))
  68. (λ (formula)
  69. (let iter ([num 0])
  70. ;; (print "trying formula for num:" num "which is:" (formula num))
  71. (cond
  72. [(prime? (formula num)) (iter (+ num 1))]
  73. [else num]))))
  74. ;; (number-of-primes (make-quadratic-formula -61 971)) is overlooked?
  75. (define find-most-primes-coeffs
  76. (λ (a-start a-end)
  77. (print "starting search for" a-start "<= a <=" a-end)
  78. (let ([limit-abs-b 1000])
  79. (let iter ([coeff-a a-start]
  80. [coeff-b (* -1 limit-abs-b)]
  81. [maximum-num-primes 0]
  82. [result (cons 0 (cons 0 0))])
  83. ;; (when (and (= coeff-a -61) (= coeff-b 971))
  84. ;; (print "a =" coeff-a
  85. ;; "and b =" coeff-b))
  86. (cond
  87. [(> coeff-b limit-abs-b)
  88. ;; increase a, reset b
  89. ;; (print "increment a to" (+ coeff-a 1))
  90. (iter (+ coeff-a 1)
  91. (* -1 limit-abs-b)
  92. maximum-num-primes
  93. result)]
  94. [(> coeff-a a-end)
  95. ;; (print "reached end of segment [" a-start ";" a-end "]" ", result is:" result)
  96. result]
  97. [else
  98. (let* ([formula (make-quadratic-formula coeff-a coeff-b)]
  99. [num-primes (number-of-primes formula)])
  100. (cond
  101. [(> num-primes maximum-num-primes)
  102. ;; (print "new maximum of produced primes for"
  103. ;; "a:" coeff-a
  104. ;; "b:" coeff-b
  105. ;; "->" num-primes)
  106. (iter coeff-a
  107. (+ coeff-b 1)
  108. num-primes
  109. (cons num-primes (cons coeff-a coeff-b)))]
  110. [else
  111. (iter coeff-a
  112. (+ coeff-b 1)
  113. maximum-num-primes
  114. result)]))])))))
  115. (define primes-and-coeffs
  116. (let ([limit-abs-a 999])
  117. (let* ([num-cores 32]
  118. [segments (segment (* -1 limit-abs-a)
  119. limit-abs-a
  120. num-cores)])
  121. ;; (print "segments:" segments)
  122. (run-in-parallel segments
  123. (λ (seg)
  124. (find-most-primes-coeffs (segment-start seg)
  125. (segment-end seg)))
  126. (λ (acc current)
  127. ;; (print "comparing result" acc "with result" current)
  128. (cond
  129. [(> (car acc) (car current))
  130. acc]
  131. [else current]))
  132. -inf.0))))
  133. (match primes-and-coeffs
  134. [(num-of-primes a . b)
  135. (print "quadratic formula with coefficients"
  136. "a =" a "and"
  137. "b =" b
  138. "has" num-of-primes "primes")
  139. (print "result:" (* a b))])