Checks the primality of consecutive odd integers in a specified range - algorithm

The following program finds the smallest integral divisor (greater than 1) of a given number n. It does this in a straightforward way, by testing n for divisibility by successive integers starting with 2.
n is prime if and only if n is its own smallest divisor.
(define (square x) (* x x))
(define (divisible? a b)
(= (remainder a b) 0))
(define (find-divisor n test)
(cond ((> (square test) n) n)
((divisible? n test) test)
(else (find-divisor n (+ test 1)))))
(define (smallest-divisor n)
(find-divisor n 2))
(define (prime? n)
(= (smallest-divisor n) n))
How to write a procedure that checks the primality of consecutive odd integers in a specified range?
(define (search_for_primes from to)
(cond ((> from to) false)
((prime? from) (display from))
(else (search_for_primes (+ 1 from) to))))
My solution just write 1 to the output.

A cond will stop at the first match and execute the corresponding expressions only. So if you execute (search_for_primes 1 xxx), 1 is erroneously identified as a prime and the procedure stops there.
What you want is something like
(define (search_for_primes from to)
(unless (> from to)
(when (prime? from)
(display from)
(display " "))
(search_for_primes (+ 1 from) to)))
where the recursion is done regardless of whether you found a prime or not.
Testing:
> (search_for_primes 2 100)
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

You should definitely start with doing an efficient sieve (like the sieve of Eratosthenes) over the range to efficiently catch multiples of small primes. If your numbers are small, just doing that up to sqrt(n) is good enough. (This is good enough for, for example, Project Euler problems.)
If your range is small and numbers large, use that to just get "likely primes", then use your favorite primality test (see https://en.wikipedia.org/wiki/Primality_test for some options) on each one.
If your range is large and your numbers are large...you've got problems. :-)

Related

calculate the sum of proper divisors of a given number in Racket BSL

Design a Racket function named findProperDivisor that takes a natural number and calculates the sum of all its proper divisors. A proper divisor of a natural number is the divisor that is strictly less than the number.
Examples:
Input: 20
Output: 22
//Proper divisors: 1 + 2 + 4 + 5 + 10 = 22
(define (sum-of-proper-divisors n i)
(cond [(= i 1) 1]
[(= (remainder n i) 0)
(+ i (sum-of-proper-divisors n (sub1 i)))]
[else (sum-of-proper-divisors n (sub1 i))]))
I found this code on this page but it gives me 1+2+4+5+10+20=42 I need 22.
I would like to write this code with one parameter by using recursion and cond. I am using Beginning Student Language (BSL), which does not have things like let defined.
Step 1: understand what the code is doing. Why is there an additional parameter? What is happening with it?
Step 2: How do you call this? What does this mean for i?
Step 3: What would you have to do differently so that the remainder is not checked against the number itself?
To fulfill the condition strictly smaller than itself, call it with (sum-of-proper-divisors 20 (sub1 20)) then you get 22, since then, 20 is not counted as divisor.
Since you should define that function with just one number as argument, - due to the constrains of this beginner-language, I would define the desired function as a second function:
(define (sum-of-proper-divisors n i)
(cond ((= 1 i) 1)
((= (remainder n i) 0)
(+ i (sum-of-proper-divisors n (sub1 i))))
(else (sum-of-proper-divisors n (sub1 i)))))
(define (findProperDivisors n)
(sum-of-proper-divisors n (sub1 n)))
(findProperDivisors 20) ;; => 22

returning a list and check conditions in scheme

I have a function sum-of-digits which calculates the sum of square digits
And stop function which check if sum-of-digits series always reach one of the stop numbers. {0 1 4 16 20 37 42 58 89 145}
How do i make a function called 's_series' that returns a list containing sum-of-digits until a stop number is reached.
ex :- (s_series 130)
(10 1)
My code
(define (s_series x)
(let ((number (sum-of-digits x)))
(if (number stop(number) 1)
((let (L '(sum)))
(s_series sum ))
L
))
how can i fix this and make it work ?
First off If you are collecting the sum-of-squared-digits then the stop? function should take such sum and not calculate it directly:
(define (stop? value)
(if (memv value '(0 1 4 16 20 37 42 58 89 145)) #t #f))
Notice I use memv since we know we are comparing numbers and memv uses eqv? to compare and thus is the right "member" function for the job. Also I don't use sum-of-squared-digits here to not do the operation twice for each element.
In the SRFI-1 List Library there is a function called unfold:
(require srfi/1) ; In #!r6rs you import (srfi :1) but I assume #lang racket
(define (s-series start)
(unfold stop? ; stop if the sum is accodring to stop?
values ; no term transformation
sum-of-squared-digits ; how to make th enext value
(sum-of-squared-digits start) ; omit the first value
(lambda (v) (list v)))) ; keep the stop value
(s-series 120)
; ==> (5 25 29 85 89)
The recommended approach is, of course, to use existing procedures (such as unfold) to solve your problem. That's the way of thinking encouraged by functional programming. For completeness' sake, let's see how we could write an equivalent solution using only basic operations, and the procedures we previously defined:
(define (s_series n)
(let ((sum (sum-of-digits n)))
(if (stop? n)
(list sum)
(cons sum (s_series sum)))))
It works as expected:
(s_series 120)
=> '(5 25 29 85 89)

SICP exercise 1.28: false negatives in the Miller-Rabin test

Exercise 1.28. One variant of the Fermat test that cannot be fooled is called the Miller-Rabin test (Miller 1976; Rabin 1980). This
starts from an alternate form of Fermat's Little Theorem, which states
that if n is a prime number and a is any positive integer less than n,
then a raised to the (n - 1)st power is congruent to 1 modulo n. To
test the primality of a number n by the Miller-Rabin test, we pick a
random number a < n and raise a to the (n - 1)st power modulo n using
the expmod procedure. However, whenever we perform the squaring step
in expmod, we check to see if we have discovered a ''nontrivial square
root of 1 modulo n,'' that is, a number not equal to 1 or n - 1 whose
square is equal to 1 modulo n. It is possible to prove that if such a
nontrivial square root of 1 exists, then n is not prime. It is also
possible to prove that if n is an odd number that is not prime, then,
for at least half the numbers a < n, computing a^(n-1) in this way will
reveal a nontrivial square root of 1 modulo n. (This is why the
Miller-Rabin test cannot be fooled.) Modify the expmod procedure to
signal if it discovers a nontrivial square root of 1, and use this to
implement the Miller-Rabin test with a procedure analogous to
fermat-test. Check your procedure by testing various known primes and
non-primes. Hint: One convenient way to make expmod signal is to have
it return 0.
(define (fast-prime? n)
(define (fast-prime-iter n counter)
(cond ((= counter 1) #t) ; There is no need to check 1
((miller-rabin-test n counter)
(fast-prime-iter n (- counter 1)))
(else
(newline)
(display counter)
#f)))
(fast-prime-iter n (- n 2)))
(define (miller-rabin-test n a)
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(nontrivial-square-root?
(remainder (square (expmod base (/ exp 2) m))
m)))
(else
(remainder (* base (expmod base (- exp 1) m))
m))))
(= (expmod a (- n 1) n) 1))
(define (nontrivial-square-root? val)
(if (= val 1)
0
val))
My idea is to filter out those so-called "nontrivial square roots of 1 modulo n" with the procedure nontrivial-square-root?. A 0 is returned if (remainder (square (expmod base (/ exp 2) m)) m) is 1, in which case the square of (expmod base (/ exp 2) m) must be equal to 1 modulo n (this is because m always equals n), making it a nontrivial square root.
While nontrivial-square-root? does filter out carmichael numbers such as 561, 1105, 1729, 2465, 2821 and 6601, prime numbers such as 7 and 13 are also reported to be composite.
What causes these false negatives?
The important part of the quote marked with bold text:
However, whenever we perform the squaring step in expmod, we check to see if we have discovered a ''nontrivial square root of 1 modulo n,'' that is, a number not equal to 1 or n - 1 whose square is equal to 1 modulo n
So before you square and take the remainder you have to check that the argument is not 1 or n - 1. This occurs, e.g., if you call (miller-rabin-test 5 3). Working the recursion out you notice that there is a call (nontrivial-square-root? (remainder (square 4) 5)) which evaluates to (nontrivial-square-root? 1). However, 5 can still be prime because 4 is 5 - 1.
So in the squaring part you can, e.g., call a following function:
(define (sqrmod-with-check val n)
(let ((sqrmod (remainder (square val) n)))
(cond ((or (= val (- n 1)) (= val 1)) sqrmod)
((= sqrmod 1) 0)
(else sqrmod))))
where the arguments are the expmod call and m. This does the square and remainder for you except in the case we have found a nontrivial square root of 1 modulo n, when it returns 0. I divided it to three conditions, instead of two, just because of readability.

Improving performance for converting numbers to lists, and base10 to base2

Many Project Euler problems require manipulating integers and their digits, both in base10 and base2. While I have no problem with converting integers in lists of digits, or converting base10 into base2 (or lists of their digits), I often find that performance is poor when doing such conversions repeatedly.
Here's an example:
First, here are my typical conversions:
#lang racket
(define (10->bin num)
(define (10->bin-help num count)
(define sq
(expt 2 count))
(cond
[(zero? count) (list num)]
[else (cons (quotient num sq) (10->bin-help (remainder num sq) (sub1 count)))]
)
)
(member 1 (10->bin-help num 19)))
(define (integer->lon int)
(cond
[(zero? int) empty]
[else (append (integer->lon (quotient int 10)) (list (remainder int 10)))]
)
)
Next, I need a function to test whether a list of digits is a palindrome
(define (is-palindrome? lon)
(equal? lon (reverse lon)))
Finally, I need to sum all base10 integers below some max that are palindromes in base2 and base10. Here's the accumulator-style function:
(define (sum-them max)
(define (sum-acc count acc)
(define base10
(integer->lon count))
(define base2
(10->bin count))
(cond
[(= count max) acc]
[(and
(is-palindrome? base10)
(is-palindrome? base2))
(sum-acc (add1 count) (+ acc count))]
[else (sum-acc (add1 count) acc)]))
(sum-acc 1 0))
And the regular recursive version:
(define (sum-them* max)
(define base10
(integer->lon max))
(define base2
(10->bin max))
(cond
[(zero? max) 0]
[(and
(is-palindrome? base10)
(is-palindrome? base2))
(+ (sum-them* (sub1 max)) max)]
[else (sum-them* (sub1 max))]
)
)
When I apply either of these two last functions to 1000000, I takes well over 10 seconds to complete. The recursive version seems a bit quicker than the accumulator version, but the difference is negligible.
Is there any way I can improve this code, or do I just have to accept that this is the style of number-crunching for which Racket isn't particularly suited?
So far, I have considered the possibility of replacing integer->lon by a similar integer->vector as I expect vector-append to be faster than append, but then I'm stuck with the need to apply reverse later on.
Making your existing code more efficient
Have you considered getting the list of bits using any of Racket's bitwise operations? E.g.,
(define (bits n)
(let loop ((n n) (acc '()))
(if (= 0 n)
acc
(loop (arithmetic-shift n -1) (cons (bitwise-and n 1) acc)))))
> (map bits '(1 3 4 5 7 9 10))
'((1) (1 1) (1 0 0) (1 0 1) (1 1 1) (1 0 0 1) (1 0 1 0))
It'd be interesting to see whether that speeds anything up. I expect it would help a bit, since your 10->bin procedure currently makes a call to expt, quotient, and remainder, whereas bit shifting, depending on the representations used by the compiler, would probably be more efficient.
Your integer->lon is also using a lot more memory than it needs to, since the append is copying most of the result at each step. This is kind of interesting, because you were already using the more memory efficient approach in bin->10. Something like this is more efficient:
(define (digits n)
(let loop ((n n) (acc '()))
(if (zero? n)
acc
(loop (quotient n 10) (cons (remainder n 10) acc)))))
> (map digits '(1238 2391 3729))
'((1 2 3 8) (2 3 9 1) (3 7 2 9))
More efficient approaches
All that said, perhaps you should consider the approach that you're using. It appears that right now, you're iterating through the numbers 1…MAX, checking whether each one is a palindrome, and if it is, adding it to the sum. That means you're doing something with MAX numbers, all in all. Rather than checking for palindromic numbers, why not just generate them directly in one base and then check whether they're a palindrome in the other. I.e., instead of of checking 1…MAX, check:
1
11
101, and 111
1001, and 1111
10001, 10101, 11011, and 11111,
and so on, up until the numbers are too big.
This list is all the binary palindromes, and only some of those will be decimal palindromes. If you can generate the binary palindromes using bit-twiddling techniques (so you're actually working with the integers), it's easy to write those to a string, and checking whether a string is a palindrome is probably much faster than checking whether a list is a palindrome.
Are you running these timings in DrRacket by any chance? The IDE slows down things quite a bit, especially if you happen to have debugging and/or profiling turned on, so I'd recommend doing these tests from the command line.
Also, you can usually improve the brute-force approach. For example, you can say here that we only have to consider odd numbers, because even numbers are never a palindrome when expressed as binaries (a trailing 0, but the way you represent them there's never a heading 0). This divides the execution time by 2 regardless of the algorithm.
Your code runs on my laptop in 2.4 seconds. I wrote an alternative version using strings and build-in functions that runs in 0.53 seconds (including Racket startup; execution time in Racket is 0.23 seconds):
#!/usr/bin/racket
#lang racket
(define (is-palindrome? lon)
(let ((lst (string->list lon)))
(equal? lst (reverse lst))))
(define (sum-them max)
(for/sum ((i (in-range 1 max 2))
#:when (and (is-palindrome? (number->string i))
(is-palindrome? (number->string i 2))))
i))
(time (sum-them 1000000))
yields
pu#pumbair: ~/Projects/L-Racket time ./speed3.rkt
cpu time: 233 real time: 233 gc time: 32
872187
real 0m0.533s
user 0m0.472s
sys 0m0.060s
and I'm pretty sure that people with more experience in Racket profiling will come up with faster solutions.
So I could give you the following tips:
Think about how you may improve the brute force approach
Get to know your language better. Some constructs are faster than others for no apparent reason
see http://docs.racket-lang.org/guide/performance.html and http://jeapostrophe.github.io/2013-08-19-reverse-post.html
use parallelism when applicable
Get used to the Racket profiler
N.B. Your 10->bin function returns #f for the value 0, I guess it should return '(0).

weirdness in scheme

I was trying to implement Fermat's primality test in Scheme.
I wrote a procedure fermat2(initially called fermat1) which returns true
when a^p-1 congruent 1(mod p) (please read it correctly guys!!)
a
every prime p number should satisfy the procedure (And hence Fermat's little theorem .. )
for any a
But when I tried to count the number of times this procedure yields true for a fixed number of trials ... ( using countt procedure, described in code) I got shocking results ans
So I changed the procedure slightly (I don't see any logical change .. may be I'm blind) and named it fermat1(replacing older fermat1 , now old fermat1 ->fermat2) and it worked .. the prime numbers passed the test all the times ...
why on earth the procedure fermat2 called less number of times ... what is actually wrong??
if it is wrong why don't I get error ... instead that computation is skipped!!(I think so!)
all you have to do , to understand what I'm trying to tell is
(countt fermat2 19 100)
(countt fermat1 19 100)
and see for yourself.
Code:
;;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))
I had real pain .. figuring out what it actually does .. please follow the code and tell why this dicrepieancies?
Even (countt fermat2 19 100) called twice returns different results.
Let's fix your fermat2 since it's shorter. Definition is: "If n is a prime number and a is any positive integer less than n, then a raised to the nth power is congruent to a modulo n.". That means f(a, n) = a^n mod n == a mod n. Your code tells f(a, n) = a^(n-1) mod n == 1 which is different. If we rewrite this according to definition:
(define (fermat2 n)
(define (tryout a x)
(= (remainder (fast-exp a x) x)
(remainder a x)))
(tryout (1+ (random n)) n))
This is not correct yet. (1+ (random n)) returns numbers from 1 to n inclusive, while we need [1..n):
(define (fermat2 n)
(define (tryout a x)
(= (remainder (fast-exp a x) x)
(remainder a x)))
(tryout (+ 1 (random (- n 1))) n))
This is correct version but we can improve it's readability. Since you're using tryout only in scope of fermat2 there is no need in parameter x to pass n - latter is already bound in scope of tryout, so final version is
(define (fermat n)
(define (tryout a)
(= (remainder (fast-exp a n) n)
(remainder a n)))
(tryout (+ 1 (random (- n 1)))))
Update:
I said that formula used in fermat2 is incorrect. This is wrong because if a*k = b*k (mod n) then a = b (mod n). Error as Vasu pointed was in generating random number for test.

Resources