Prime Numbers

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’. :wink: 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. :wink:

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