123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- (library (lib math)
- (export even?
- odd?
- sum
- sum-up-to
- range-sum
- square
- factorial
- factorial-linear
- digits
- digit?
- contains-digit?
- remove-digit
- count-digits
- digits-sum
- digits-unique?
- digits->real
- integer->digits
- digits->integer
- +decimal-digits+
- divides?
- factors
- fib
- int/
- integer-divide-arbitrary-precision
- rational-repeating-decimals-length
- natural-number?)
- (import
- (except (rnrs base) let-values map odd? even?)
- (only (guile)
- lambda* λ
- map
- ;; math stuff
- remainder
- inexact->exact
- display
- simple-format
- string-join
- string-append
- null?
- memv)
- (only (srfi srfi-1) reduce)
- (srfi srfi-69) ; hash tables
- (srfi srfi-1) ; remove
- (lib list-helpers)
- (contract)
- (lib print-utils))
- (define inc
- (λ (num)
- (+ num 1)))
- (define sum
- (λ (nums)
- "Sum all numbers in the given list nums."
- (reduce + 0 nums)))
- (define sum-up-to
- (λ (n)
- "Sums up integers from including 1 to including the given
- number n."
- (/ (* n (+ n 1))
- 2)))
- (define range-sum
- (λ (start end)
- "Calculate the sum of all integers from including start to
- including end."
- (+ (- (sum-up-to end)
- (sum-up-to start))
- start)))
- (define even?
- (λ (num)
- "Check, if a number is even."
- (= (remainder num 2) 0)))
- (define odd?
- (λ (num)
- "Check, if a number is odd."
- (= (remainder num 2) 1)))
- (define square
- (λ (num)
- "Calculate the square of a number."
- (* num num)))
- (define factorial
- (λ (num)
- "Calculate the factorial of a number using a linear recursive
- process."
- (if (= num 1)
- 1
- (* num
- (factorial (- num 1))))))
- (define factorial-linear
- (λ (num)
- "Calculate the factorial of a number using a linear iterative
- process."
- (let iter ([current-num 1]
- [product 1])
- (cond
- [(> current-num num) product]
- [else
- (iter (+ current-num 1)
- (* product current-num))]))))
- (define char->number
- (λ (char)
- (string->number
- (list->string
- (list char)))))
- (define digits
- (λ (num)
- "Get the digits of a number."
- (map char->number
- (string->list (number->string num)))))
- (define integer->digits digits)
- (define digit?
- (λ (num)
- (and (natural-number? num)
- (< num 10))))
- (define contains-digit?
- (λ (num digit)
- "Check whether the number contains the digit."
- ;; `memv` returns a list, if the item is in the list
- ;; and #f otherwise.
- (pair?
- (memv digit (digits num)))))
- (define-with-contract remove-digit
- (require (integer? num)
- (digit? digit))
- (ensure (integer? <?>))
- (λ (num digit)
- (digits->integer
- (let iter ([digits° (digits num)])
- (cond
- [(null? digits°) '()]
- [(= (first digits°) digit)
- (drop digits° 1)]
- [else
- (cons (first digits°)
- (iter (drop digits° 1)))])))))
- (define-with-contract count-digits
- (require (integer? num))
- (ensure (integer? <?>) (positive? <?>))
- (λ (num)
- "Get the number of digits in an integer number."
- (string-length (number->string num))))
- (define digits-sum
- (λ (num)
- "Calculate the sum of the digits of a number."
- (sum (digits num))))
- (define divides?
- (λ (a b)
- "Check, whether the given number a divides the given number b."
- (= (remainder b a) 0)))
- (define factors
- (lambda* (num #:key (trivial-factors #f))
- "Calculate the list of all factors of the given number num."
- (let ([limit (inexact->exact (floor (/ num 2)))]
- [start 2])
- (let iter ([potential-factor start]
- [factors-lst (if trivial-factors '(1) '())])
- (cond
- [(> potential-factor limit)
- (if trivial-factors
- (cons num factors-lst)
- factors-lst)]
- [(divides? potential-factor num)
- (iter (+ potential-factor 1)
- (cons potential-factor factors-lst))]
- [else
- (iter (+ potential-factor 1)
- factors-lst)])))))
- (define digits-unique?
- (λ (num)
- (unique-items? (digits num))))
- (define +decimal-digits+
- '(0 1 2 3 4 5 6 7 8 9))
- (define-with-contract fib
- (require (positive? n) (integer? n))
- (ensure (positive? <?>) (integer? <?>))
- (λ (n)
- (let iter ([prev-prev-fib 0] [prev-fib 1] [counter 1])
- (cond
- [(= counter n)
- prev-fib]
- [else
- (iter prev-fib (+ prev-prev-fib prev-fib) (+ counter 1))]))))
- (define int/
- (λ (numer denom)
- "Perform a whole integer division of a/b."
- (/ (- numer (remainder numer denom))
- denom)))
- (define-with-contract digits->real
- (require (list? digits)
- (not (null? digits))
- (integer? (car digits)))
- (ensure (real? <?>))
- (λ (digits)
- (string->number
- (string-append (number->string (car digits))
- "."
- (string-join (map number->string (cdr digits)) "")))))
- (define-with-contract digits->integer
- (require (list? digits)
- (not (null? digits))
- (integer? (car digits)))
- (ensure (integer? <?>))
- (λ (digits)
- (string->number
- (string-join (map number->string digits)
- ""))))
- (define-with-contract integer-divide-arbitrary-precision
- (require (integer? numer)
- (integer? denom)
- (not (zero? denom)))
- (ensure (list? <?>))
- (lambda* (numer denom #:key (precision 16))
- (let iter ([numer numer]
- [numer-digits° (cdr (digits numer))]
- [counter 0])
- (let ([rem (remainder numer denom)]
- [factor (int/ numer denom)]
- [next-numer-part
- (if (null? numer-digits°)
- 0
- (car numer-digits°))]
- [next-numer-digits
- (if (null? numer-digits°)
- '()
- (cdr numer-digits°))])
- ;; (print denom "fits into" numer factor "times." "remainder" rem)
- (cond
- [(> counter precision) '()]
- [(= rem 0) (list factor)]
- [else
- (cons factor
- (iter (+ (* rem 10) next-numer-part)
- next-numer-digits
- (+ counter 1)))])))))
- ;; EXAMPLE:
- ;; 1 : 17 = 0.05...
- ;; 0
- ;; -v
- ;; 10
- ;; 0
- ;; --v
- ;; 100
- ;; 85
- ;; ---v
- ;; 150
- (define-with-contract rational-repeating-decimals-length
- (require (rational? fraction)
- (= (numerator fraction) 1)
- (not (zero? (denominator fraction))))
- (ensure (integer? <?>)
- (or (positive? <?>)
- (zero? <?>)))
- (λ (fraction)
- (print "fraction:" fraction "=" "...")
- (let ([denom (denominator fraction)])
- (let iter ([numer (numerator fraction)]
- ;; Create a hash table storing how many digits ago
- ;; a pair of factor and remainder was seen.
- [seen-table (make-hash-table equal?)])
- (let ([rem (remainder numer denom)]
- [factor (int/ numer denom)])
- (print numer "/" denom "=" factor "R" rem)
- (cond
- ;; If the remainder ever becomes 0, then the digits end
- ;; there. There is no infinitely repeating digit
- ;; sequence.
- [(= rem 0) 0]
- ;; If the remainder has already been seen, then we know
- ;; the digits will repeat.
- [(hash-table-exists? seen-table rem)
- ;; The remainder has already been seen, but how many
- ;; digits ago was it? Look it up in the hash table.
- (hash-table-ref seen-table rem)]
- ;; If the remainder has not yet been seen, mark it as
- ;; seen, and increase the distance of all previously seen
- ;; factor-remainder pairs by 1.
- [else
- ;; (display (simple-format #f "seen remainder: ~a\n" rem))
- (hash-table-set! seen-table rem 0)
- (hash-table-walk seen-table
- (λ (key val)
- ;; (print "increasing distance for:" key)
- (hash-table-update! seen-table key inc)))
- ;; Iterate. Times 10 for the next position in the
- ;; decimals.
- (iter (* rem 10) seen-table)]))))))
- (define natural-number?
- (λ (num)
- (and (integer? num)
- (or (zero? num)
- (positive? num))))))
|