Sieve of Eratosthenes with Wheel Factorization - c++

I'm implementing a reasonably fast prime number generator and I obtained some nice results with a few optimizations on the sieve of Eratosthenes. In particular, during the preliminary part of the algorithm, I skip all multiples of 2 and 3 in this way:
template<class Sieve, class SizeT>
void PrimeGenerator<Sieve, SizeT>::factorize()
{
SizeT c = 2;
m_sieve[2] = 1;
m_sieve[3] = 1;
for (SizeT i=5; i<m_size; i += c, c = 6 - c)
m_sieve[i] = 1;
}
Here m_sieve is a boolean array according to the sieve of Eratosthenes.
I think this is a sort of Wheel factorization only considering primes 2 and 3, incrementing following the pattern 2, 4, 2, 4,..
What I would like to do is to implement a greater wheel, maybe considering primes 2,3 and 5.
I already read a lot of documentation about it, but I didn't see any implementation with the sieve of Eratosthenes... a sample code could help a lot, but also some hints would be nice :)
Thanks.

You can go even further. Here is some OCaml code I wrote a few years ago:
let eratosthene borne =
let remove_multiples a lst =
let rec remmult multa li accu = function
[] -> rev accu
| head::tail ->
if multa = head
then remmult (a*(hd li)) (tl li) accu tail
else remmult multa li (head::accu) tail
in
remmult (a * a) lst [] lst
in
let rec first_primes accu ll =
let a = hd ll in
if a * a > borne then (rev accu) # ll
else first_primes (a::accu) (remove_multiples a (tl ll))
in
let start_list =
(* Hard code of the differences of consecutive numbers that are prime*)
(* with 2 3 5 7 starting with 11... *)
let rec lrec = 2 :: 4 :: 2 :: 4 :: 6 :: 2 :: 6 :: 4 :: 2 :: 4 :: 6
:: 6 :: 2 :: 6 :: 4 :: 2 :: 6 :: 4 :: 6 :: 8 :: 4 :: 2 :: 4 :: 2
:: 4 :: 8 :: 6 :: 4 :: 6 :: 2 :: 4 :: 6 :: 2 :: 6 :: 6 :: 4 :: 2
:: 4 :: 6 :: 2 :: 6 :: 4 :: 2 :: 4 :: 2 :: 10 :: 2 :: 10 :: lrec
and listPrime2357 a llrec accu =
if a > borne then rev accu
else listPrime2357 (a + (num (hd llrec))) (tl llrec) (a::accu)
in
listPrime2357 (num 11) lrec []
in
first_primes [(num 7);(num 5);(num 3);(num 2)] start_list;;
Note the nice trick that OCaml allows for cyclic linked list.

Paul Pritchard, an Australian mathematician working for IBM, developed a series of wheel sieves in the 1980s. I discuss one of them at my blog, including examples worked by hand and an implementation in Scheme. It's too big to discuss here. You should be aware that though the asymptotic complexity is less than the Sieve of Eratosthenes, implementation details typically make it slower in practice.

2*3*5 = 30
spokes = 2,3,4,5,6,8,9,10,12,15,16,18,20,24,30
numbers between spokes: 1,7,11,13,17,19,23,25,29
int[] gaps = [6,4,2,4,2,4,2,4];
int[] primes = [2,3,5];
int max = 9001;
int counter, max_visited;
while(max_visited < max) {
int jump = gaps[counter];
counter = counter + 1 % gaps.length;
max_visited += jump;
}
Does that help?
Alternatively, this might have been what you wanted instead, pseudo-code:
primes = [2,3,5];
product = multiply(primes);//imaginary function that returns 30
wheel = new int[product];
foreach(prime in primes)
for(int x = 1; x <= product/prime; x++)
wheel[prime*x] = 1;
return wheel

There's a much better optimisation of it (it takes O(n) operations instead of O(n log log n) for your variant): https://stackoverflow.com/a/17550147/2559094 , but it takes more memory (uses n + n/log n memory instead of n).
If you still want to go on with your optimisation and consider primes p1, p2, ..., pn, you should write all numbers from 0 to p1*p2*...*pn (use lcm in case you decide to use not only prime numbers) and check which of them satisfy the following system:
x != 0 (mod p1)
x != 0 (mod p2)
...
x != 0 (mod pn)
Then you should find all the gaps between these numbers and make an array of those gaps to use them.

Related

How to do a binomial expansion with either plus or minus sign

Is there a way to expand a binomial expression with either a plus or minus sign between the two terms? e.g. (x+y)^3 ; (x-y)^5
I did
program binom
implicit none
integer :: nth = 5, i, pow1, pow2, comb
character(100) :: strpow1, strpow2, comb1, var1='x', var2='y'
do i=0, nth
pow1=(nth-i)
pow2=(i)
write(strpow1,'(i10)') pow1
write(strpow2,'(i10)') pow2
comb=cnr(nth,i)
write(comb1,'(i10)') comb
write(*,'(7a)') comb1, var1,"^",strpow1,var2,"^",strpow2
end do
contains
integer function cnr(n,r)
implicit none
integer, intent(in) :: n,r
integer :: i, ans
integer :: large, small
if ((n-r) > r) then
large = n - r
small = r
else
large = r
small = n - r
end if
ans = 1
do i = large+1, n
ans = ans*i
end do
do i = 2, small
ans = ans/i
end do
cnr = ans
end function cnr
end program binom
It wasn't the right code at all. Btw, the code inside the function was given to us.

Splitting a list in non-equal width chunks in Haskell [duplicate]

This question already has answers here:
No instance for (Floating Int)
(3 answers)
Closed 6 years ago.
I am trying to do something like in Haskell:
mkList start end nb_chunck will output [start, boun1, bound2, bound3 ..., end]
However I don't want to split the list in equal-size chunk but to follow a logarithmic scale.
The C algorithm I want to transform in Haskell is availabke here: How to get a logarithmic distribution from an interval
I don't really know how to do it.
Here's what I have attempted so far:
mkList :: Int -> Int -> Int -> Int -> Int -> [Int]
mkList _ _ _ _ 7 = []
mkList lower upper start end n = [lower, ((fromIntegral (log(2 + (fromIntegral n :: Int)) )+start) * scale)] ++ (mkList (fromIntegral(((fromIntegral (log(2 + (fromIntegral n :: Int)) )+start) * scale)+1) :: Int) ((fromIntegral (log(2 + (fromIntegral (n) :: Int)) )+start) * scale) (start) end (fromIntegral (n+1) :: Int)) where
scale = (end - start) `quot` floor(log(1 + (6)))
However, I can't validate this code, because when I compile, error messages pop up:
haskell_par3.hs:71:58:
No instance for (Floating Int) arising from a use of `log'
Possible fix: add an instance declaration for (Floating Int)
In the first argument of `fromIntegral', namely
`(log (2 + (fromIntegral n :: Int)))'
In the first argument of `(+)', namely
`fromIntegral (log (2 + (fromIntegral n :: Int)))'
In the first argument of `(*)', namely
`(fromIntegral (log (2 + (fromIntegral n :: Int))) + start)'
ghc -cpp: /usr/hs/ghc/7.6.3/bin/ghc failure (return code=1)
I've tried to make use of fromIntegral at different spots but it didn't help, as seen in other answered questions on StackOverflow.
So I'm asking two things:
Do you have any precise idea of how I could fix these compilation errors? (I know it has something to do with fromIntegral, but I can't get rid of this error).
And more important: Do you think this code may achieve what I want to do? If no, do you have any suggestions?
you can do something like this to create a log scale intervals
scale k n = map (floor . (*k) . (/(log n)) . log) [1..n]
e.g.
scale 100 9
[0,31,50,63,73,81,88,94,100]
and use the indices to partition the array by start/end indices.
You can cast the output to [Int] since floor convert it to an Integral type
Prelude> scale 10 3 :: [Int]
[0,6,10]
Prelude> :t it
it :: [Int]

How to add an Int to a list of Int while passing the list as an argument?

I want to generate a list of the first n fibonacci numbers.
I have 3 functions:
fib2: generates the n-th number
fib: calls fib2 to make a list of
those numbers
fibonacci: only exists so you don't have to pass that
empty list every time
My problem is pretty simple, but I just can't figure it out.
The line
fib n m = fib (n-1) m : (fib2 n)
does not work especially the part "m : (fib2 n)". I want to calculate the n-th fibonacci number (with fib2 n) and add it to my list of fibonacci numbers m. I thought ":" adds a new element to a list, but somehow I am using it wrong.
Below the whole code
fib2 :: Int -> Int
fib2 0 = 1
fib2 1 = 1
fib2 n = fib2 (n - 1) + fib2 (n - 2)
fib :: Int -> [Int] -> [Int]
fib 0 m = m
fib n m = fib (n-1) m : (fib2 n)
fibonacci :: Int -> [Int]
fibonacci n = fib n []
Okay I found out I'm an idiot. I have to switch the arguments of the ":" function
fib n m = fib (n-1) (fib2 n : m)
and everything is fine.

How to get integers from list where sum of them is less than X?

Sorry for the mess that was here.
I wanted a classic greedy algorithm for knapsack problem in haskell for integers.
But there was other question - how to refer to list in list comprehension?
There are several approaches to this:
Generate all lists which are smaller. Take the longest
For every n <= X, generate [1..n] and check whether its sum is lesser x. Take the longest of those sets:
allLists x = takeWhile ( (<=x) . sum) $ inits [1..]
theList = last . allLists
where inits is from Data.List
Alternatively, we remember mathematics
We know that the sum of [1..n] is n*(n+1)/2. We want x >= n * (n+1)/2. We solve for n and get that n should be 0.5 * (sqrt (8 * x + 1) - 1). Since that's not a natural number, we floor it:
theList x = [1..n]
where n = floor $ 0.5 * (sqrt (8 * (fromIntegral x) + 1) - 1)
This will give all the lists that its sum is not greater than 100:
takeWhile (\l -> sum l <= 100) $ inits [1..]

Prime factorizacion in haskell

I'm making a program that, for a given integer n, returns a list of a pair of integers, where the first element is a prime from the prime factorization of n, and the second element is the corresponding exponent of that prime. For example for n = 50, it would output [(2,1),(5,2)], since 50 =(2^1)*(5^2).
So anyway, this is my code:
--returns all numbers that divide x
divis :: Integer -> [Integer]
divis 1 = []
divis x = [n | n<-[2..(x-1)], mod x n == 0]
--checks if a number is prime
isprime :: Integer -> Bool
isprime 1 = False
isprime n = if divis n == [] then True else False
--list of prime numbers that divide x
facto :: Integer -> [Integer]
facto 1 = []
facto x = [n | n <- (divis x), isprime n == True]
--finds the biggest exponent of a number m that divides another number n
potencia :: Integer -> Integer -> Integer
potencia _ 0 = error "error"
potencia _ 1 = error "error"
potencia n m = (head [x | x <- [0..], not(mod n (m^x) == 0)]) - 1
The next step would be that, for a number n, I can put togheter in a pair for each number in facto n its corresponding exponent, and output that.
I have tried with this:
factorizar :: Integer -> [(Integer, Integer)]
factorizar 0 = error "nope"
factorizar 1 = [(1,1)] --This isn't accurate but I'll change it later
factorizar n = [(x,y) | x<-(facto n), y == potencia n x, mod n (x^y) == 0] --THIS
I know, the y part in the set comprehension is ugly everywhere. The thing is I dont know what to use since for defining y I need to use x as well, but it is part of the set comprehension. I have tried changing it, or using 'where' but it always has a problem with 'y', telling me it's not in the scope or something. What could be an elegant solution for this?
The simple answer is
y == potencia n x
should really read
let y = potencia n x
and you don't need to check that mod n (x^y) == 0 - I think it is going to be true by definition of potencia.
There are other things you could do differently, but they are tidy-ups.