计划中的怪异

时间:2011-03-06 13:57:40

标签: scheme

我试图在Scheme中实现Fermat的素性测试。 我写了一个程序fermat2(最初称为fermat1),它返回true 什么时候^ p-1全等1(mod p)(请正确读一读!!) 一个

每个素数p都应该满足程序(因此Fermat的小定理......) 任何一个

但是当我试图计算这个程序在固定数量的试验中产生真实的次数...(使用countt程序,在代码中描述)我得到了令人震惊的结果

所以我稍微改变了程序(我没有看到任何逻辑上的改变......可能是我失明了)并命名为fermat1(取代旧的fermat1,现在是旧的fermat1 - > fermat2)它工作..素数一直通过测试......

为什么地球上的程序fermat2调用的次数少......实际上是什么错误? 如果它是错的,为什么我不会得到错误...而是跳过计算!!(我想是这样!)

所有你需要做的,了解我想说的是

(countt fermat2 19 100)
(countt fermat1 19 100)

亲眼看看。

代码:

;;Guys this is really weird
;;I might not be able to explain this
;;just try out
;;(countt fermat2 19 100) 
;;(countt fermat1 19 100)
;;compare both values ...
;;did you get any error using countt with fermat2,if yes please specify why u got error
;;if it was because of reminder procedure .. please tell your scheme version

;;created on 6 mar 2011 by fedvasu
;;using mit-scheme 9.0 (compiled from source/microcode)
;; i cant use a quote it mis idents (unfriendly stack overflow!)
;;fermat-test based on fermat(s) little theorem a^p-1 congruent to 1 (mod p) p is prime
;;see MIT-SICP,or Algorithms by Vazirani or anyother number theory book

;;this is the correct logic of fermat-test (the way it handles 0)
 (define (fermat1 n)
     (define (tryout a x)
;; (display "I've been called\n")
      (= (remainder (fast-exp a (- x 1)) x) 1))
                    ;;this exercises the algorithm
                    ;;1+ to avoid 0
       (define temp (random n))
       (if (= temp 0)
     (tryout (1+ temp) n)
     (tryout temp n)))

;;old fermat-test
;;which is wrong
;;it doesnt produce any error!!
;;the inner procedure is called only selective times.. i dont know when exactly 
;;uncomment the display line to see how many times tryout is called (using countt)
;;i didnt put any condition when it should be called
;;rather it should be every time fermat2 is called
;;how is it so??(is it to avoid error?)
  (define (fermat2 n)
   (define (tryout a x)
     ;; (display "I've been called\n")
      (= (remainder (fast-exp a (- x 1)) x) 1))
                     ;;this exercises the algorithm
                     ;;1+ to avoid 0
                    (tryout (1+ (random n)) n))

;;this is the dependency procedure for fermat1 and fermat2
;;this procedure calculates base^exp (exp=nexp bcoz exp is a keyword,a primitive)
;;And it is correct :)
  (define (fast-exp base nexp)
   ;;this is iterative procedure where a*b^n = base^exp is constant always
   ;;A bit tricky though
    (define (logexp a b n)
      (cond ((= n 0) a);;only at the last stage a*b^n is not same as base^exp
         ((even? n) (logexp a (square b) (/ n 2)))
         (else (logexp (* a b) b (- n 1)))))

        (logexp 1 base nexp))


 ;;utility procedure which takes a procedure and its argument and an extra 
 ;; argument times which tells number of times to call
 ;;returns the number of times result of applying proc on input num yielded true
 ;;counting the number times it yielded true
 ;;procedure yields true for fixed input,
 ;;by calling it fixed times)
 ;;uncommenting display line will help
   (define (countt proc num times)
     (define (pcount p n t c)
             (cond ((= t 0)c)
                ((p n );; (display "I'm passed by fermat1\n")
                (pcount p n (- t 1) (+ c 1)));;increasing the count
                 (else c)))
        (pcount proc num times 0))

我真的很痛苦......搞清楚它实际上是做什么的......请按照代码说明为什么会出现这种情况?

1 个答案:

答案 0 :(得分:2)

偶数(countt fermat2 19 100)调用两次会返回不同的结果。

让我们修复你的fermat2,因为它更短。定义是:“如果n是素数而a是任何小于n的正整数,那么提升到n次幂与模n一致。”这意味着f(a, n) = a^n mod n == a mod n。您的代码告诉f(a, n) = a^(n-1) mod n == 1哪个不同。如果我们根据定义重写它:

(define (fermat2 n)
  (define (tryout a x)
    (= (remainder (fast-exp a x) x) 
       (remainder a x)))

  (tryout (1+ (random n)) n))

这还不正确。 (1+ (random n))会返回从1到n的数字,而我们需要[1..n)

(define (fermat2 n)
  (define (tryout a x)
    (= (remainder (fast-exp a x) x) 
       (remainder a x)))

  (tryout (+ 1 (random (- n 1))) n))

这是正确的版本,但我们可以提高它的可读性。由于您仅在fermat2的范围内使用tryout,因此参数x无需传递n - 后者已经绑定在tryout的范围内,因此最终版本是

(define (fermat n)
  (define (tryout a)
    (= (remainder (fast-exp a n) n) 
       (remainder a n)))

  (tryout (+ 1 (random (- n 1)))))

<强>更新

我说fermat2中使用的公式不正确。这是错误的,因为a*k = b*k (mod n)然后是a = b (mod n)。 Vasu指出的错误是生成随机数进行测试。