math.scm 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. (define-module (euler math))
  2. (define-public (factorial n)
  3. (let loop ((i 1) (acc 1))
  4. (if (> i n) acc
  5. (loop (1+ i) (* i acc)))))
  6. ;; Fast enough for single calculations
  7. (define-public (proper-divisors n)
  8. (let lp ([i (inexact->exact (floor (/ n 2)))] [divisors '()])
  9. (if (zero? i) divisors
  10. (lp (1- i)
  11. (if (zero? (modulo n i))
  12. (cons i divisors)
  13. divisors)))))
  14. ;; I'm curious what's faster: setting, or remaking...
  15. ;; I should really learn how to do speed tests...
  16. (define-public (proper-divisors-in-range limit)
  17. (define divisor-array (make-array '() (1+ limit)))
  18. (define (add-divisor-lp divisor)
  19. (let lp ([div-multiple (+ divisor divisor)])
  20. (unless (> div-multiple limit)
  21. (array-set! divisor-array
  22. (cons divisor
  23. (array-ref divisor-array
  24. div-multiple))
  25. div-multiple)
  26. (lp (+ div-multiple divisor)))))
  27. (do [(i 1 (1+ i))]
  28. [(> i limit) divisor-array]
  29. (add-divisor-lp i)))
  30. (define-public (relative-primes n)
  31. (let loop ([i 1] [acc '()])
  32. (if (> i n) acc
  33. (loop (1+ i)
  34. (if (= 1 (gcd n i))
  35. (cons i acc)
  36. acc)))))
  37. ;; DEPRECATED, it seems like guile already implemented a fast expt function
  38. (define-public (expt-fast base step)
  39. (let lp ([base base] [step step] [acc 1])
  40. (cond
  41. [(zero? step) 1]
  42. [(= 1 step) (* acc base)]
  43. [else
  44. (lp (* base base)
  45. (if (even? step) (/ step 2)
  46. (/ (1- step) 2))
  47. (if (even? step) acc
  48. (* acc base)))])))