Primality Checking
May 1, 2009
Although the math looks difficult, the code is quite straight forward. Check?
calculates r and s in the outer loop, checks if as is 1 modulo n, and then the inner loop checks the other condition for each j from 0 to r-1.
(define (check? a n)
(let loop ((r 0) (s (- n 1)))
(if (even? s) (loop (+ r 1) (/ s 2))
(if (= (expm a s n) 1) #t
(let loop ((j 0) (s s))
(cond ((= j r) #f)
((= (expm a s n) (- n 1)) #t)
(else (loop (+ j 1) (* s 2)))))))))
Then prime?
tests a few boundary conditions and performs fifty random calls to check?
.
(define (prime? n)
(cond ((< n 2) #f) ((= n 2) #t) ((even? n) #f)
(else (let loop ((k 50))
(cond ((zero? k) #t)
((not (check? (randint 1 n) n)) #f)
(else (loop (- k 1))))))))
Expm
(modular exponentiation) and randint
come from the Standard Prelude. A quick test shows that 289-1 = 618970019642690137449562111 is prime:
> (prime? (- (expt 2 89) 1))
#t
You can run this code at http://codepad.org/rSDxFrZn.
[…] Praxis – Primality Checking By Remco Niemeijer Today’s Programming Praxis problem is about checking whether or not a number is prime. We’re supposed […]
My Haskell solution (see http://bonsaicode.wordpress.com/2009/05/01/programming-praxis-primality-checking/ for a version with comments):
import Control.Arrow
import Data.Bits
import Data.List
import System.Random
isPrime :: Integer -> StdGen -> Bool
isPrime n g =
let (s, d) = (length *** head) . span even $ iterate (flip div 2) (n – 1)
xs = map (expm n d) . take 50 $ randomRs (2, n – 2) g
in all (\x -> elem x [1, n – 1] ||
any (== n – 1) (take s $ iterate (expm n 2) x)) xs
expm :: Integer -> Integer -> Integer -> Integer
expm m e b = foldl’ (\r (b’, _) -> mod (r * b’) m) 1 .
filter (flip testBit 0 . snd) .
zip (iterate (flip mod m . (^ 2)) b) $
takeWhile (> 0) $ iterate (flip shiftR 1) e
main :: IO ()
main = print . isPrime (2 ^ 89 – 1) =<< getStdGen [/sourcecode]
I’m slowly working my way through old exercises now that I have some free time. Here’s
my attempt in Common Lisp; I’m trying to learn the language, even though I already had Pythoned Miller-Rabin previously.
Wow, so much code needed in OCaml to solve this exercise in a self-contained fashion! First of all, a general-purpose function to return a random
Big_int
between 0 and a specifiedmax
(exclusive):(You can’t go much lower level than this.) Next, some utility functions on
Big_int
s:Finally, an imperative-style Rabin-Miller test:
Two optimizations were applied: first, the random a should be greater than 1; second, the successive powers of a in the inner loop are calculated inductively by (modular) squaring.
I made a mistake in
random_big_int
. Lines 10 and 11 are wrong, they should read:This is a Haskell program I wrote (ironically enough around May 2009, though I hadn’t heard about this website back then.) This was my first relatively non-trivial Haskell program.
To test 2^89 -1 use,
.\miller-rabin.exe -t 618970019642690137449562111
Rewrote the Haskell Miller-Rabin in Clojure as my first Clojure program. It is line-by-line translation, pretty much. Main difference is that one can’t generate random numbers > 2^63, so that is taken into account when generating tests.
{
{前几天|最近|这段时间|这些天|前段时间|前些日子|没多久前|不久前}刚开始{碰|啃|练习|接触|学|接触到|学习} python,现在{碰到|遇到|遭遇到|接触到|要用到}验证码问题,{网上|上网}{查了下|google了一下|百度了一下|谷歌了一下|baidu了一下|百度了一会|谷歌了一会|google了一会|搜了一下|搜了一会}{相关|}{内容|知识|资料|教程},{知道|得知|获悉|了解到|了解|好像|似乎}用python获取验证码{的人|}还是{比较多的|不少|不在少数|挺多的|}。自己琢磨了{一番|一下|一下午|一整天|一早上|一晚上|整个上午|整个下午|整个晚上},用的是{开源的|免费的|不用钱的|不用银子的|不用付费的}打码工具tesseractor,但{始终|最后|最终|后来|至今|到现在|到目前}都没{搞出来|搞定|成功|获取验证码|成功获取验证码|获取到验证码|弄出验证码|解决验证码问题|搞出验证码},{不知道|不清楚|不了解|不明白|没弄懂|没明白|没了解|没搞清|没搞懂|没搞明白}是什么{问题|原因|情况},难道是{免费没好货|免费的问题|天下没有免费的午餐}?{有没有|有无|知不知|知不知道|有人知道|有没人知道|有没谁知道|有谁知道|有谁了解|有谁用过}{什么|哪个|哪些|哪一些|哪个}付费的{推荐|软件|平台|应用|工具}吗?
|
{前几天|最近|这段时间|这些天|前段时间|前些日子|没多久前|不久前}刚开始{碰|啃|练习|接触|学|接触到|学习}
python,现在{碰到|遇到|遭遇到|接触到|要用到}验证码问题,{通过|测试了下|弄了下|搞了下}本地可以{解析|获取|弄|搞|读取|读}出{一个|}字符串,{然后|但是|可是|接着|不过}再提交{的时候|后|之后|过后|以后}这个验证码已经{变|改变|变化}了,{我|}{在这里|在这|现在|如今}想{问|咨询|询问|了解|搞明白|弄懂}的是{如何|怎样|怎么}{才|}能{保证|保持}这两{者|个}{一致|相同|不变|}。