math.scm 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. (library (lib math)
  2. (export even?
  3. odd?
  4. sum
  5. sum-up-to
  6. range-sum
  7. square
  8. factorial
  9. factorial-linear
  10. digits
  11. digit?
  12. contains-digit?
  13. remove-digit
  14. count-digits
  15. digits-sum
  16. digits-unique?
  17. digits->real
  18. integer->digits
  19. digits->integer
  20. +decimal-digits+
  21. divides?
  22. factors
  23. fib
  24. int/
  25. integer-divide-arbitrary-precision
  26. rational-repeating-decimals-length
  27. natural-number?)
  28. (import
  29. (except (rnrs base) let-values map odd? even?)
  30. (only (guile)
  31. lambda* λ
  32. map
  33. ;; math stuff
  34. remainder
  35. inexact->exact
  36. display
  37. simple-format
  38. string-join
  39. string-append
  40. null?
  41. memv)
  42. (only (srfi srfi-1) reduce)
  43. (srfi srfi-69) ; hash tables
  44. (srfi srfi-1) ; remove
  45. (lib list-helpers)
  46. (contract)
  47. (lib print-utils))
  48. (define inc
  49. (λ (num)
  50. (+ num 1)))
  51. (define sum
  52. (λ (nums)
  53. "Sum all numbers in the given list nums."
  54. (reduce + 0 nums)))
  55. (define sum-up-to
  56. (λ (n)
  57. "Sums up integers from including 1 to including the given
  58. number n."
  59. (/ (* n (+ n 1))
  60. 2)))
  61. (define range-sum
  62. (λ (start end)
  63. "Calculate the sum of all integers from including start to
  64. including end."
  65. (+ (- (sum-up-to end)
  66. (sum-up-to start))
  67. start)))
  68. (define even?
  69. (λ (num)
  70. "Check, if a number is even."
  71. (= (remainder num 2) 0)))
  72. (define odd?
  73. (λ (num)
  74. "Check, if a number is odd."
  75. (= (remainder num 2) 1)))
  76. (define square
  77. (λ (num)
  78. "Calculate the square of a number."
  79. (* num num)))
  80. (define factorial
  81. (λ (num)
  82. "Calculate the factorial of a number using a linear recursive
  83. process."
  84. (if (= num 1)
  85. 1
  86. (* num
  87. (factorial (- num 1))))))
  88. (define factorial-linear
  89. (λ (num)
  90. "Calculate the factorial of a number using a linear iterative
  91. process."
  92. (let iter ([current-num 1]
  93. [product 1])
  94. (cond
  95. [(> current-num num) product]
  96. [else
  97. (iter (+ current-num 1)
  98. (* product current-num))]))))
  99. (define char->number
  100. (λ (char)
  101. (string->number
  102. (list->string
  103. (list char)))))
  104. (define digits
  105. (λ (num)
  106. "Get the digits of a number."
  107. (map char->number
  108. (string->list (number->string num)))))
  109. (define integer->digits digits)
  110. (define digit?
  111. (λ (num)
  112. (and (natural-number? num)
  113. (< num 10))))
  114. (define contains-digit?
  115. (λ (num digit)
  116. "Check whether the number contains the digit."
  117. ;; `memv` returns a list, if the item is in the list
  118. ;; and #f otherwise.
  119. (pair?
  120. (memv digit (digits num)))))
  121. (define-with-contract remove-digit
  122. (require (integer? num)
  123. (digit? digit))
  124. (ensure (integer? <?>))
  125. (λ (num digit)
  126. (digits->integer
  127. (let iter ([digits° (digits num)])
  128. (cond
  129. [(null? digits°) '()]
  130. [(= (first digits°) digit)
  131. (drop digits° 1)]
  132. [else
  133. (cons (first digits°)
  134. (iter (drop digits° 1)))])))))
  135. (define-with-contract count-digits
  136. (require (integer? num))
  137. (ensure (integer? <?>) (positive? <?>))
  138. (λ (num)
  139. "Get the number of digits in an integer number."
  140. (string-length (number->string num))))
  141. (define digits-sum
  142. (λ (num)
  143. "Calculate the sum of the digits of a number."
  144. (sum (digits num))))
  145. (define divides?
  146. (λ (a b)
  147. "Check, whether the given number a divides the given number b."
  148. (= (remainder b a) 0)))
  149. (define factors
  150. (lambda* (num #:key (trivial-factors #f))
  151. "Calculate the list of all factors of the given number num."
  152. (let ([limit (inexact->exact (floor (/ num 2)))]
  153. [start 2])
  154. (let iter ([potential-factor start]
  155. [factors-lst (if trivial-factors '(1) '())])
  156. (cond
  157. [(> potential-factor limit)
  158. (if trivial-factors
  159. (cons num factors-lst)
  160. factors-lst)]
  161. [(divides? potential-factor num)
  162. (iter (+ potential-factor 1)
  163. (cons potential-factor factors-lst))]
  164. [else
  165. (iter (+ potential-factor 1)
  166. factors-lst)])))))
  167. (define digits-unique?
  168. (λ (num)
  169. (unique-items? (digits num))))
  170. (define +decimal-digits+
  171. '(0 1 2 3 4 5 6 7 8 9))
  172. (define-with-contract fib
  173. (require (positive? n) (integer? n))
  174. (ensure (positive? <?>) (integer? <?>))
  175. (λ (n)
  176. (let iter ([prev-prev-fib 0] [prev-fib 1] [counter 1])
  177. (cond
  178. [(= counter n)
  179. prev-fib]
  180. [else
  181. (iter prev-fib (+ prev-prev-fib prev-fib) (+ counter 1))]))))
  182. (define int/
  183. (λ (numer denom)
  184. "Perform a whole integer division of a/b."
  185. (/ (- numer (remainder numer denom))
  186. denom)))
  187. (define-with-contract digits->real
  188. (require (list? digits)
  189. (not (null? digits))
  190. (integer? (car digits)))
  191. (ensure (real? <?>))
  192. (λ (digits)
  193. (string->number
  194. (string-append (number->string (car digits))
  195. "."
  196. (string-join (map number->string (cdr digits)) "")))))
  197. (define-with-contract digits->integer
  198. (require (list? digits)
  199. (not (null? digits))
  200. (integer? (car digits)))
  201. (ensure (integer? <?>))
  202. (λ (digits)
  203. (string->number
  204. (string-join (map number->string digits)
  205. ""))))
  206. (define-with-contract integer-divide-arbitrary-precision
  207. (require (integer? numer)
  208. (integer? denom)
  209. (not (zero? denom)))
  210. (ensure (list? <?>))
  211. (lambda* (numer denom #:key (precision 16))
  212. (let iter ([numer numer]
  213. [numer-digits° (cdr (digits numer))]
  214. [counter 0])
  215. (let ([rem (remainder numer denom)]
  216. [factor (int/ numer denom)]
  217. [next-numer-part
  218. (if (null? numer-digits°)
  219. 0
  220. (car numer-digits°))]
  221. [next-numer-digits
  222. (if (null? numer-digits°)
  223. '()
  224. (cdr numer-digits°))])
  225. ;; (print denom "fits into" numer factor "times." "remainder" rem)
  226. (cond
  227. [(> counter precision) '()]
  228. [(= rem 0) (list factor)]
  229. [else
  230. (cons factor
  231. (iter (+ (* rem 10) next-numer-part)
  232. next-numer-digits
  233. (+ counter 1)))])))))
  234. ;; EXAMPLE:
  235. ;; 1 : 17 = 0.05...
  236. ;; 0
  237. ;; -v
  238. ;; 10
  239. ;; 0
  240. ;; --v
  241. ;; 100
  242. ;; 85
  243. ;; ---v
  244. ;; 150
  245. (define-with-contract rational-repeating-decimals-length
  246. (require (rational? fraction)
  247. (= (numerator fraction) 1)
  248. (not (zero? (denominator fraction))))
  249. (ensure (integer? <?>)
  250. (or (positive? <?>)
  251. (zero? <?>)))
  252. (λ (fraction)
  253. (print "fraction:" fraction "=" "...")
  254. (let ([denom (denominator fraction)])
  255. (let iter ([numer (numerator fraction)]
  256. ;; Create a hash table storing how many digits ago
  257. ;; a pair of factor and remainder was seen.
  258. [seen-table (make-hash-table equal?)])
  259. (let ([rem (remainder numer denom)]
  260. [factor (int/ numer denom)])
  261. (print numer "/" denom "=" factor "R" rem)
  262. (cond
  263. ;; If the remainder ever becomes 0, then the digits end
  264. ;; there. There is no infinitely repeating digit
  265. ;; sequence.
  266. [(= rem 0) 0]
  267. ;; If the remainder has already been seen, then we know
  268. ;; the digits will repeat.
  269. [(hash-table-exists? seen-table rem)
  270. ;; The remainder has already been seen, but how many
  271. ;; digits ago was it? Look it up in the hash table.
  272. (hash-table-ref seen-table rem)]
  273. ;; If the remainder has not yet been seen, mark it as
  274. ;; seen, and increase the distance of all previously seen
  275. ;; factor-remainder pairs by 1.
  276. [else
  277. ;; (display (simple-format #f "seen remainder: ~a\n" rem))
  278. (hash-table-set! seen-table rem 0)
  279. (hash-table-walk seen-table
  280. (λ (key val)
  281. ;; (print "increasing distance for:" key)
  282. (hash-table-update! seen-table key inc)))
  283. ;; Iterate. Times 10 for the next position in the
  284. ;; decimals.
  285. (iter (* rem 10) seen-table)]))))))
  286. (define natural-number?
  287. (λ (num)
  288. (and (integer? num)
  289. (or (zero? num)
  290. (positive? num))))))