我们把1.22和1.24两个找素数的过程融合,变成找carmichael数的方法,也就是一个数通过所有的费马检查,但是不通过最小因数检查。以下是变更后的过程。
#lang racket
(define (square x) (* x x))
(define (runtime) ( current-inexact-milliseconds ))
(define(smallest-divisor n)
(find-divisor n 2))
(define(find-divisor n test-divisor)
(cond((>(square test-divisor) n ) n)
((divides? test-divisor n) test-divisor)
(else(find-divisor n (+ test-divisor 1)))))
(define(divides? a b)
(=(remainder b a) 0))
(define (prime? n)
(= n (smallest-divisor n)))
(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))))
(define (fermat-test n a)
(= (expmod a n n) a))
(define (fast-prime? n times)
(cond ((= times 0) #t)
((fermat-test n times) (fast-prime? n (- times 1)))
(else #f)))
(define (timed-carmichael-test n)
(start-carmichael-test n (runtime)))
(define (start-carmichael-test n start-time)
(if (and (fast-prime? n (- n 1)) (not (prime? n)))
(begin (report-prime n (- (runtime) start-time)) #t) #f))
(define(report-prime n elapsed-time)
(newline)
(display n)
(display " usetime ")
(display elapsed-time))
(define (search-for-carmichael n count)
(cond((= count 0) n )
((timed-carmichael-test n) (search-for-carmichael (+ n 1) (- count 1)))
(else (search-for-carmichael (+ n 1) count))))
(search-for-carmichael 500 10)
找出大于500的10个Carmichael数,跟书上面写的是一致的结果,不过为什么注释说10000000里面有255个这种数,计算机人对255天生敏感吧,这些数可能具备某些神奇的二进制数特质,暂时不做研究了。
561 usetime 0.975830078125
1105 usetime 0.976806640625
1729 usetime 1.952880859375
2465 usetime 4.88232421875
2821 usetime 9.763427734375
6601 usetime 17.57373046875
8911 usetime 26.3583984375
10585 usetime 44.912353515625
15841 usetime 48.81640625
29341 usetime 75.57153320312529342