(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (* (expmod base (/ exp 2) m)
(expmod base (/ exp 2) m))
m))
(else (remainder (* base (expmod base (- exp 1) m))
m))))
; Runtime is O(exp) not O(log(exp))
; Rather than cutting the problem size in half 1-2 iterations, this procedure
; creates two problems with halve the size.
;
; To see why expmod has linear runtime
; Consider the runtime for exp = n vs 2n
; Let T = the runtime for exp = n
;
; (expmod base 2n modulus) evaluates expmod twice for exp = n
; and does O(1) extra work (e.g. checking if exp is even, computing a product
; and remainder). Thus the runtime is >2T, and expmod has Omega(n) runtime.
;
; Note: g(n) is Omega(f(n)) means g(n) > c*f(n) for some c and all sufficiently
; large n
;
; The recurrences for slow expmod vs fast expmod are:
; T(n) = 2T(n/2) + 1 vs T(n) = T(n/2) + 1
; with solutions
; T(n) is O(n) vs T(n) is O(log(n))