123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- ;; https://projecteuler.net/problem=6
- ;; Sum square difference
- ;; Problem 6
- ;; The sum of the squares of the first ten natural numbers
- ;; is, $$1^2 + 2^2 + ... + 10^2 = 385$$
- ;; The square of the sum of the first ten natural numbers
- ;; is, $$(1 + 2 + ... + 10)^2 = 55^2 = 3025$$
- ;; Hence the difference between the sum of the squares of
- ;; the first ten natural numbers and the square of the sum
- ;; is $3025 - 385 = 2640$.
- ;; Find the difference between the sum of the squares of the
- ;; first one hundred natural numbers and the square of the
- ;; sum.
- (import
- (except (rnrs base) let-values)
- (only (guile) lambda* λ)
- (srfi srfi-1)
- (contract)
- (lib segment)
- (lib parallelism)
- (prefix (lib math) math:))
- (define-with-contract sum-of-squares
- (require (>= start 0)
- (>= end 0)
- (< start end)
- (integer? start)
- (integer? end))
- (ensure (> <?> 0)
- (integer? <?>))
- (λ (start end)
- (let iter ([sum 0] [num start])
- (cond
- [(= num end)
- (+ sum (math:square num))]
- [else
- (iter (+ sum (math:square num))
- (+ num 1))]))))
- (define get-sum-of-squares
- (λ (segments)
- (run-in-parallel segments
- ;; Calculate the sum of squares
- ;; for each segment.
- (λ (seg)
- (sum-of-squares (segment-start seg)
- (segment-end seg)))
- ;; Sum up all the sums.
- (λ (acc current)
- (+ acc current))
- ;; Sum starts with 0.
- 0)))
- (define get-square-of-sums
- (λ (segments)
- ;; Calculate square of sums.
- (math:square
- (run-in-parallel segments
- ;; Calculate the sum for each
- ;; segment.
- (λ (seg)
- (math:range-sum (segment-start seg)
- (segment-end seg)))
- ;; Sum all segment sums.
- (λ (acc current)
- (+ acc current))
- ;; Sum starts with 0.
- 0))))
- (define-with-contract diff-sum-sq-sq-sum
- (require (>= start 0)
- (>= end 0)
- (< start end))
- (ensure (> <?> 0))
- (λ (start end)
- ;; First split the range into segments.
- (let ([segment-count 8])
- (let ([segments (segment start end segment-count)])
- (abs
- (- (get-sum-of-squares segments)
- (get-square-of-sums segments)))))))
- (let* ([start 1]
- [end (expt 10 2)])
- (display
- (simple-format
- #f "~a\n"
- (diff-sum-sq-sq-sum start end))))
|