the only way i can tink of is writing all the prime numbers but that wont work
There’s probably a faster way but this works:
set the_primes to {}
repeat with i from 1 to 1000
if check_prime(i) then set end of the_primes to i
end repeat
return the_primes
on check_prime(the_num)
repeat with i from 2 to (the_num - 1)
if the_num mod i = 0 then return false
end repeat
return true
end check_prime
Jon
Using a slightly modified version of the script above, this code will create a list of the first 1,000 prime numbers. It also adds some slight validation to the subroutine for checking the number:
set the_primes to {}
set i to 1
set start_time to (current date)
repeat until ((count of the_primes) = 1000)
set i to i + 1
if check_prime(i) then set end of the_primes to i
end repeat
display dialog ("It took " & ((current date) - start_time) & " seconds to get the first 1,000 prime numbers.") buttons {"OK"} default button 1 with icon 1 giving up after 10
return the_primes
on check_prime(the_num)
try
set the_num to the_num as integer
repeat with i from 2 to (the_num - 1)
if the_num mod i = 0 then return false
end repeat
return true
on error
return false
end try
end check_prime
On my PB G4 1.25GHz running Mac OS X 10.3.2, this took 18 seconds.
Jon
thanks
one other thing my uncle cant see very well and he wants to know if ther is some way to get Mail to read him his emails when he opens them.
This slight modification makes a big difference in terms of speed (especially when testing larger numbers):
set the_primes to {}
set i to 1
set start_time to (current date)
repeat until ((count of the_primes) = 1000)
set i to i + 1
if check_prime(i) then set end of the_primes to i
end repeat
display dialog ("It took " & ((current date) - start_time) & " seconds to get the first 1,000 prime numbers.") buttons {"OK"} default button 1 with icon 1 giving up after 10
return the_primes
on check_prime(the_num)
try
set the_num to the_num as integer
set max_num to (round of (the_num / 2) rounding up)
repeat with i from 2 to max_num
if the_num mod i = 0 then return false
end repeat
return true
on error
return false
end try
end check_prime
As to reading the email, sure, that’s pretty easy. Create a script that is run on any received email (or at least on emails from known senders) that grabs the subject, sender, and content and uses the “say” command to speak that text. Lots of examples for each of these steps can be found by searching these boards.
Jon
i couldnt find any
Try again.
Jon
Hi Jonn8,
You don’t have to go higher than the square root of a number. Say z is the number and z is divisible by x. Let x> z^0.5 and z=x*y. Then it’s easy to see that y<z^0.5. So all you need to do is divide by primes less than or equal to the square root.
Nice tip, Kel. Now the following routine takes 3 seconds (down from 18 & 11 for the code above) on my machine:
set the_primes to {}
set i to 1
set start_time to (current date)
repeat until ((count of the_primes) = 1000)
set i to i + 1
if check_prime(i) then set end of the_primes to i
end repeat
display dialog ("It took " & ((current date) - start_time) & " seconds to get the first 1,000 prime numbers.") buttons {"OK"} default button 1 with icon 1 giving up after 10
return the_primes
on check_prime(the_num)
try
set the_num to the_num as integer
set max_num to (round of (the_num ^ 0.5) rounding up)
repeat with i from 2 to max_num
if the_num mod i = 0 then return false
end repeat
return true
on error
return false
end try
end check_prime
Jon
It’ll go even faster if you use my rndUp() handler instead of ‘round … rounding up’. In fact, though, since the square root’s the upper limit of the search, there’s no point in going past it. It’s good enough to round down using ‘div 1’.
Another tip is that you don’t need to test even numbers. In the first repeat, you could set i to i + 2 instead of to i + 1. Also, your handler doesn’t recognise 1 or 2 as prime numbers. I imagine the ‘as integer’ coercion in the ‘try’ block is to catch fractional numbers, but (I’m told) ‘as integer’ rounds to nearest as from 10.3 and doesn’t error. Here’s a reworking of the script for your consideration:
set the_primes to {1, 2, 3}
set i to 3
set start_time to (current date)
set cnt to 3
repeat until cnt = 1000
set i to i + 2
if check_prime(i) then
set end of the_primes to i
set cnt to cnt + 1
end if
end repeat
display dialog ("It took " & ((current date) - start_time) & " seconds to get the first 1,000 prime numbers.") buttons {"OK"} default button 1 with icon 1 giving up after 10
return the_primes
on check_prime(the_num)
if the_num div 1 = the_num and the_num > 0 then
if the_num > 3 then
set max_num to (the_num ^ 0.5) div 1
repeat with i from 2 to max_num
if the_num mod i = 0 then return false
end repeat
end if
return true
else
return false
end if
end check_prime
Michael Sullivan, Arthur Knapp, and I were having a three-sided e-mail converstation a couple of years ago about finding primes. Michael had some “wheel” system which greatly reduced the amount of work such a script actually had to do. I’ll see if I can find it.
FYI
Sieve of Eratosthenes – an algorythm for finding prime numbers.
I came across this years ago. I have found very good explanations on the web.
Brad Bumgarner, CTA
Nicely done, NG. 1, however, is usually not considered a prime number.
Jon
testIt()
on testIt()
-- this is the first step, getting your test number in
display dialog "Wanna know if its Prime?" default answer "8 or less digits unless u are stupid"
-- here we have to test for valid input
try
set testPrime to (text returned of result) as number
on error
display dialog ¬
"Wow that wasn't a number...." buttons {"OK"} default button "OK" with icon stop
retryMe()
end try
if class of testPrime is real then
display dialog "hehe stupid! i sadi nothing over 8 digits" buttons {"OK"} ¬
default button "OK" with icon caution
retryMe()
end if
-- here we raise a flag for negative numbers
if testPrime < 0 then
set theFlag to -1
else
set theFlag to 1
end if
-- here we handle the exceptions
if testPrime is in {2, -2} then
set testPrime to testPrime as string
display dialog testPrime & ¬
" is a prime number." buttons {"OK"} default button "OK"
retryMe()
else if testPrime is in {1, 0, -1} then
set testPrime to testPrime as string
display dialog testPrime & ¬
" is not a prime number." buttons {"OK"} default button "OK"
retryMe()
-- here we test for even numbers
else if (testPrime mod 2) = 0 then
display dialog ¬
"Even numbers whose magnitude
greater than 2 are never prime
DUH!!! haha you are so stupid…unless your are me…" buttons {“OK”} default button “OK” with icon stop
retryMe()
-- here we test for primeness
else
repeat with inc from 3 to ¬
(2 * (((testPrime * theFlag) ^ (1 / 2)) div 2) + 1) ¬
by 2
if (testPrime mod inc) = 0 then
set testPrime to testPrime as string
display dialog testPrime & " is not a prime number as
it has a divisor of " & inc buttons {"OK"} ¬
default button "OK"
retryMe()
end if
end repeat
set testPrime to testPrime as string
display dialog testPrime & ¬
" Yep its prime." buttons {"OK"} default button "OK"
retryMe()
end if
end testIt
– home of the retry handler
on retryMe()
display dialog “Do you want to try again?”
testIt()
end retryMe
there
No. I’m not usually, either, but I get by.
Arthur’s (and Michael’s?) GetPrimes() handler turns out to have been based on that. It makes a list of all the integers from 2 to a given target and then “crosses out” the ones that aren’t primes. As it returns all the primes in a given range, it’s not strictly comparable with Jon’s handler, which returns a specified number of primes.
on GetPrimes(m) -- NG's optimisation
(*
* m == An upper boundary positive integer, return all prime numbers
* from 2 to m, inclusive.
*)
try
set m to (m div 1) -- rounds down and coerces to integer
on error
error ("GetPrimes( integerParam )" & return & return & "The parameter must be an integer.")
end try
script o
property p : {2} -- "Serge" script-object encapsulation
end script
repeat with i from 3 to m by 2
set o's p's end to i -- initialize sieve (odd numbers only)
end repeat
set listLen to (m + 1) div 2 -- the length of the list
set zapped to missing value
repeat with i from 2 to ((m ^ 0.5) div 1) -- no factors if none <= square root
tell o's p's item i
if (it is not zapped) then
repeat with j from ((it ^ 2) div 2 + 1) to listLen by it
set o's p's item j to zapped
end repeat
end if
end tell
end repeat
return o's p's integers
end GetPrimes
Michael’s and Arthur’s IsPrime() handler is quite a beast and I’m not quite sure how it works, but it’s very fast at deciding whether or not an input number is a prime, even when it’s very large. It seems to be a mathematical shorthand based on known early primes and the likelihood of the number being a multiple of one of these:
on IsPrime(n)
(*
* Wheel Factorization, brillantly implemented by Michael Sullivan:
*
* n == any numerical value.
*)
if (n's class is not in {integer, real}) then error ("IsPrime( n )" & return & return & "Parameter is not a number.")
if n is not equal to n div 1 then
return false
else if (n < 2) then
return false
else if n = 2 then
return true
else if (n mod 2) = 0 then
return false
else if (n < 20) then
if n is in {9, 15} then
return false
else
return true
end if
else if (n mod 3) = 0 then
return false
else if (n mod 5) * (n mod 7) * (n mod 11) = 0 then
return false
else if ((n mod 13) * (n mod 17) * (n mod 19) * (n mod 23) * (n mod 29) = 0) then
if n is in {23, 29} then
return true
else
return false
end if
else
repeat with i from 30 to ((n ^ 0.5) div 1) by 30
if ((n mod (i + 1)) * (n mod (i + 7)) * (n mod (i + 11)) * (n mod (i + 13)) * (n mod (i + 17)) * (n mod (i + 19)) * (n mod (i + 23)) * (n mod (i + 29)) = 0) then return false
end repeat
return true
end if
end IsPrime