LUA PRIME CALCULATOR using preprocessing based on Sieve of Eratosthenes
This article shows a lua script to calculate an ordered prime list starting with 2, 3, 5, 7, etc.
We are going to improve former lua prime calculator using a preprocessing table.
This table will allow us to discard quickly some numbers and its multiples.
Within this lua script, first we perform some preprocessing, and after that actual prime testing for remaining numbers are performed.
Sieve of Eratosthenes
Sieve of Eratosthenes is an algorithm to calculate a prime number list up to a chosen number.
In this program we will use this algorithm to generate a preprocessing table.
Some examples are useful to show how preprocessing table works:
Tables are generated using a sequence with first prime numbers.
E.g:
Preprocessing table for 2
{2}
So we will test numbers this way:
We start with number one, and sum to it the first number from preprocessing table:
1+2 = 3 (3 is the next number to test for primality)
Once preprocessing table has completed, we start from first element again (2):
3+2 = 5
5+2 = 7
7+2 = 9
etc
Preprocessing table for 2 and 3:
{4,2}
First number to test:
1+4 = 5
5+2 = 7
We start again from the beginning of the table:
7+4 = 11
11+2 = 13
13+4 = 17
17+2 = 19
etc
Preprocessing table for 2, 3 and 5:
[6,4,2,4,2,4,6,2]
1+6 = 7
7+4 = 11
11+2 = 13
13+4 = 17
17+2 = 19
19+4 = 23
23+6 = 29
29+2 = 31
After reaching last element in the table we start again:
31+6 = 37
37+4 = 41
41+2 = 43
43+4 = 47
47+2 = 49
etc
Increasing the preprocessing table has an exponential cost in memory size and cpu cycles, and improvements for big preprocessing tables are small.
No preprocess at all: (No numbers are discarded) 1/1 -> 100% cost
2 {2} 1/2 -> 50% We test only 50% of numbers.
2,3 {2,4} 2/6 -> 33% We test 33% of numbers.
2,3,5 {6,4,2,4,2,4,6,2} 8/30 -> 26.6% We test 26.6% of numbers.
...
PREPROCESSING FUNCTION
Let's look at the preprocess function code:
local preproc = {2}
local primes = {2}
local function preprocess()
-- We know always prime number calculated using the preprocessing table is a prime
-- get next prime
local k = 1
local next = preproc[1] + k
print("next: "..next)
table.insert(primes, next)
-- Each level table size is multiplied by last prime number added.
local new_preproc = {}
for i=1,next do
for j=1,#preproc do
table.insert(new_preproc, preproc[j])
end -- for
end -- for
preproc = new_preproc
-- This loop removes from the table multiples of last added prime number
local next_n = 1
local l = 1
local second = 1
local next_big = next * second
new_preproc={}
carry = 0
for i=1,#preproc do
next_n = next_n + preproc[i]
if(next_n < next_big) then
table.insert(new_preproc, preproc[i]+carry)
carry = 0
else
while(next_n > next_big) do
second = second + preproc[l]
l = l + 1
next_big = next * second
end -- while
if(next_n < next_big) then
table.insert(new_preproc, preproc[i]+carry)
carry = 0
elseif(next_n == next_big) then
second = second + preproc[l]
l = l + 1
next_big = next * second
carry = carry + preproc[i]
end -- if
end -- if
end -- for
preproc = new_preproc
end -- function
Every time preprocess function is called, a prime is added to primes list, and preproc table is increased as necessary.
Its increase in memory size and cpu cycles required is exponential.
EXECUTING THE SCRIPT
Copy following code in a file: prime_calculator.lua
$ chmod a prime_calculator.lua # Give execution permissions to it.$ ./prime_calculator.lua 10000 5or
$ ./prime_calculator 10000 5 + # If there is a third argument then prime list result it is shown in the end.$ ./prime_calculator 10000 5 means: perform 5 preprocessing levels and then calculate first 10000 prime numbers.LUA CODE
#! /usr/bin/lua
local top = tonumber(arg[1])
local top_prep = tonumber(arg[2])
local preproc = {2}
local primes = {2}
local function preprocess()
-- get next prime
local k = 1
local next = preproc[1] + k
print("next: "..next)
table.insert(primes, next)
local new_preproc = {}
for i=1,next do
for j=1,#preproc do
table.insert(new_preproc, preproc[j])
end -- for
end -- for
preproc = new_preproc
local next_n = 1
local l = 1
local second = 1
local next_big = next * second
new_preproc={}
carry = 0
for i=1,#preproc do
next_n = next_n + preproc[i]
if(next_n < next_big) then
table.insert(new_preproc, preproc[i]+carry)
carry = 0
else
while(next_n > next_big) do
second = second + preproc[l]
l = l + 1
next_big = next * second
end -- while
if(next_n < next_big) then
table.insert(new_preproc, preproc[i]+carry)
carry = 0
elseif(next_n == next_big) then
second = second + preproc[l]
l = l + 1
next_big = next * second
carry = carry + preproc[i]
end -- if
end -- if
end -- for
preproc = new_preproc
end -- function
for j=1,top_prep do
preprocess()
end
local total_prep = #preproc
local total = #primes
local sqrt = math.sqrt
local pos = 1
local i = 1 + preproc[pos]
while(total<top) do
local is_prime = true
local max = sqrt(i)
for j=1, total do
local div = primes[j]
if(div>max) then
break
end
if(i%div==0) then
is_prime = false
break
end
end
if(is_prime) then
table.insert(primes, i)
total = total + 1
end
pos = pos + 1
if(pos>total_prep) then pos=1 end
i = i + preproc[pos]
end -- while
if(arg[3]~=nil) then
for i=1,# primes do
print(primes[i])
end
endREFERENCE
Sieve of Eratosthenes (Wikipedia)
YOU MAY ALSO BE INTERESTED IN:
Lua: Calculate a prime number list
Calculate a PRIME number LIST using C language
0 comentarios:
Post a Comment