我试图在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))
我真的很痛苦......搞清楚它实际上是做什么的......请按照代码说明为什么会出现这种情况?
答案 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指出的错误是生成随机数进行测试。