我的迭代expmod实现有什么问题?

时间:2016-11-23 04:45:49

标签: algorithm iteration lisp primes sicp

以下程序旨在计算base^expo mod m

(define (expmod base expo m)
  (define (square n)
    (* n n))
  (define (even? n)
    (= (remainder n 2) 0))
  (define (expmod-iter base expo m result)
    (cond ((= expo 0) result)
          ((even? expo)
           (expmod-iter base
                        (/ expo 2)
                        m
                        (remainder (square result) m)))
          (else
            (expmod-iter base
                         (- expo 1)
                         m
                         (remainder (* base result) m)))))
  (expmod-iter base expo m 1))

事实上,我试图将a tail-recursive program from SICP转换为其迭代等价物。这是原始计划:

(define (expmod base exp m)
  (cond ((= exp 0) 1)
        ((even? exp)
         (remainder (square (expmod base (/ exp 2) m))
                    m))
        (else
         (remainder (* base (expmod base (- exp 1) m))
                    m))))  

(expmod 42 1000000007 1000000007)的结果是270001056,但根据Fermat's Little Theorem,由于1000000007是素数,因此结果应为42。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

这是我对迭代expmod

的实现
(define (expmod base exp mod)
  (let loop ((base base)
             (exp exp)
             (result 1))
    (cond ((zero? exp) result)
          ((odd? exp) (loop base (sub1 exp) (modulo (* result base) mod)))
          (else (loop (modulo (sqr base) mod) (quotient exp 2) result)))))

使用您的样本输入在Racket中进行测试。如果您不使用Racket,则需要使用合适的实现替换sub1sqr

请注意,虽然你必须对偶数指数的基数进行平方,但你可以实际修改结果,正如你在我的代码中看到的那样。所以它不会太大。