SISGEV error despite allocating memory on heap? (generating primes) - c++

I have written code to generate prime numbers in a range (using a modified Sieve of Eratosthenes) , as competitive programming. The code works fine on my Visual Studio, but gives a SISGEV on the website. I use this,
static bool *prime = new bool[1000000001];
to declare memory. And can not understand the reason behind the SISGEV.
Below is the function, whose parameters are the lower limit m, and the upper limit n.
Elements of index >m which are not prime are marked false.
static bool *prime = new bool[1000000009];
void SieveOfEratosthenes(int m, int n)
{
// Create a boolean array "prime[0..n]" and initialize
// all entries it as true. A value in prime[i] will
// finally be false if i is Not a prime, else true.
memset(prime, true, n + 11);
int m2;
if (m > 10) {
m2 = m / 10;
m2 = m2 * 10;
m2 = (2 * m2) / 5;
}
else
m2 = 4;
prime[1] = false;
prime[2] = true;
prime[3] = true;
prime[5] = true;
for (int i = m2; i <= n; i += 2) {
if ( (5*2)/2 >= n) break;
prime[i] = false;
prime[(3 * i) / 2] = false;
prime[(5 * i) / 2] = false;
}
int m3;
m3 = m % 7;
m3 = m - m3;
for (int p = 7; (p)*(p) <= n; p += 6) {
// If prime[p] is not changed, then it is a prime
if (prime[p] == true) {
// Update all multiples of p,
for (int i = p; i <= n; i += p) {
prime[m3+i] = false; //cout << i << " ";
if (prime[m3 + p+ 4]) prime[((p+4)*i)/p] = false;
if (prime[m3 + p + 6]) prime[((p+6)*i)/p] = false;
}
}
prime[7] = true;
prime[11] = true;
prime[13] = true;
}
// Print all prime numbers
for (int p = m; p <= n; p++)
if (prime[p])
cout << p << endl;
}
int main() {
//other code
delete[] prime;
}

Your pointer is a static variable. In C++ the initialization of a static variable happens only once. The delete[] statement however, is executed for every function call.
Do not tilt at windmills and use std::vector instead of rolling a raw-memory solution.
A simple implementation using std::vector: (Adding the extended functionality is left as an exercise to the reader.)
#include <vector>
#include <cmath>
#include <cstddef>
#include <algorithm>
#include <iostream>
std::vector<std::size_t> eratosthenes(std::size_t const n)
{
std::vector<bool> A(n, true);
std::vector<std::size_t> r;
auto const limit = static_cast<std::size_t>(
std::ceil(std::sqrt(static_cast<double>(n))));
// check all numbers up to sqrt(n)
for (std::size_t i = 2; i <= limit; ++i)
{
// if i is prime,
if (A[i])
{
// i is prime, put it into return vector
r.push_back(i);
// set all multiples of i (below n) to false
for (std::size_t j = i*i; j < n; j+=i)
{
A[j] = false;
}
}
}
// fill rest of the primes > sqrt(n) into r
if (!r.empty())
{
for (auto i = limit+1u; i < n; ++i)
{
if (A[i]) r.push_back(i);
}
}
return r;
}
Printing it:
int main()
{
for (auto v : eratosthenes(120))
{
std::cout << v << "\n";
}
return 0;
}

Related

compact form of many for loop in C++

I have a piece of code as follows, and the number of for loops is determined by n which is known at compile time. Each for loop iterates over the values 0 and 1. Currently, my code looks something like this
for(int in=0;in<2;in++){
for(int in_1=0;in_1<2;in_1++){
for(int in_2=0;in_2<2;in_2++){
// ... n times
for(int i2=0;i2<2;i2++){
for(int i1=0;i1<2;i1++){
d[in][in_1][in_2]...[i2][i1] =updown(in)+updown(in_1)+...+updown(i1);
}
}
// ...
}
}
}
Now my question is whether one can write it in a more compact form.
The n bits in_k can be interpreted as the representation of one integer less than 2^n.
This allows easily to work with a 1-D array (vector) d[.].
In practice, an interger j corresponds to
j = in[0] + 2*in[1] + ... + 2^n-1*in[n-1]
Moreover, a direct implementation is O(NlogN). (N = 2^n)
A recursive solution is possible, for example using
f(val, n) = updown(val%2) + f(val/2, n-1) and f(val, 0) = 0.
This would correspond to a O(N) complexity, at the condition to introduce memoization, not implemented here.
Result:
0 : 0
1 : 1
2 : 1
3 : 2
4 : 1
5 : 2
6 : 2
7 : 3
8 : 1
9 : 2
10 : 2
11 : 3
12 : 2
13 : 3
14 : 3
15 : 4
#include <iostream>
#include <vector>
int up_down (int b) {
if (b) return 1;
return 0;
}
int f(int val, int n) {
if (n < 0) return 0;
return up_down (val%2) + f(val/2, n-1);
}
int main() {
const int n = 4;
int size = 1;
for (int i = 0; i < n; ++i) size *= 2;
std::vector<int> d(size, 0);
for (int i = 0; i < size; ++i) {
d[i] = f(i, n);
}
for (int i = 0; i < size; ++i) {
std::cout << i << " : " << d[i] << '\n';
}
return 0;
}
As mentioned above, the recursive approach allows a O(N) complexity, at the condition to implement memoization.
Another possibility is to use a simple iterative approach, in order to get this O(N) complexity.
(here N represents to total number of data)
#include <iostream>
#include <vector>
int up_down (int b) {
if (b) return 1;
return 0;
}
int main() {
const int n = 4;
int size = 1;
for (int i = 0; i < n; ++i) size *= 2;
std::vector<int> d(size, 0);
int size_block = 1;
for (int i = 0; i < n; ++i) {
for (int j = size_block-1; j >= 0; --j) {
d[2*j+1] = d[j] + up_down(1);
d[2*j] = d[j] + up_down(0);
}
size_block *= 2;
}
for (int i = 0; i < size; ++i) {
std::cout << i << " : " << d[i] << '\n';
}
return 0;
}
You can refactor your code slightly like this:
for(int in=0;in<2;in++) {
auto& dn = d[in];
auto updown_n = updown(in);
for(int in_1=0;in_1<2;in_1++) {
// dn_1 == d[in][in_1]
auto& dn_1 = dn[in_1];
// updown_n_1 == updown(in)+updown(in_1)
auto updown_n_1 = updown_n + updown(in_1);
for(int in_2=0;in_2<2;in_2++) {
// dn_2 == d[in][in_1][in_2]
auto& dn_2 = dn_1[in_2];
// updown_n_2 == updown(in)+updown(in_1)+updown(in_2)
auto updown_n_2 = updown_n_1 + updown(in_2);
.
.
.
for(int i2=0;i2<2;i1++) {
// d2 == d[in][in_1][in_2]...[i2]
auto& d2 = d3[i2];
// updown_2 = updown(in)+updown(in_1)+updown(in_2)+...+updown(i2)
auto updown_2 = updown_3 + updown(i2);
for(int i1=0;i1<2;i1++) {
// d1 == d[in][in_1][in_2]...[i2][i1]
auto& d1 = d2[i1];
// updown_1 = updown(in)+updown(in_1)+updown(in_2)+...+updown(i2)+updown(i1)
auto updown_1 = updown_2 + updown(i1);
// d[in][in_1][in_2]...[i2][i1] = updown(in)+updown(in_1)+...+updown(i1);
d1 = updown_1;
}
}
}
}
}
And make this into a recursive function now:
template<std::size_t N, typename T>
void loop(T& d) {
for (int i = 0; i < 2; ++i) {
loop<N-1>(d[i], updown(i));
}
}
template<std::size_t N, typename T, typename U>
typename std::enable_if<N != 0>::type loop(T& d, U updown_result) {
for (int i = 0; i < 2; ++i) {
loop<N-1>(d[i], updown_result + updown(i));
}
}
template<std::size_t N, typename T, typename U>
typename std::enable_if<N == 0>::type loop(T& d, U updown_result) {
d = updown_result;
}
If your type is int d[2][2][2]...[2][2]; or int*****... d;, you can also stop when the type isn't an array or pointer instead of manually specifying N (or change for whatever the type of d[0][0][0]...[0][0] is)
Here's a version that does that with a recursive lambda:
auto loop = [](auto& self, auto& d, auto updown_result) -> void {
using d_t = typename std::remove_cv<typename std::remove_reference<decltype(d)>::type>::type;
if constexpr (!std::is_array<d_t>::value && !std::is_pointer<d_t>::value) {
// Last level of nesting
d = updown_result;
} else {
for (int i = 0; i < 2; ++i) {
self(self, d[i], updown_result + updown(i));
}
}
};
for (int i = 0; i < 2; ++i) {
loop(loop, d[i], updown(i));
}
I am assuming that it is a multi-dimensional matrix. You may have to solve it mathematically first and then write the respective equations in the program.

How can I sort array elements by number of divisors?

My problem is that I hit an obstacle while I was solving some exercises.
The source of the problem is that I have to write a program which sort descending an array by the number of each element's divisors, but when two element has the same number of divisors it should sort ascending those values.
My code so far:
#include <iostream>
#include <fstream>
using namespace std;
int cntDiv(int n) //get number of divisors
{
int lim = n;
int c = 0;
if(n == 1)
return 1;
for(int i = 1; i < lim; i++)
{
if(n % i == 0)
{
lim = n / i;
if(lim != i)
c++;
c++;
}
}
return c;
}
int main()
{
ifstream fin("in.txt");
int n, i, j;
fin >> n;
int v[n];
for(i = 0; i < n; i++)
fin >> v[i];
int div[n];
for(i = 0; i < n; i++)
div[i] = cntDiv(v[i]);
for(i = 0; i < n - 1; i++)
{
for(j = i + 1; j < n; j++)
{
if(div[i] < div[j] && div[i] != div[j]) //if the number of divisors are different
{
int t = v[i];
v[i] = v[j];
v[j] = t;
t = div[i];
div[i] = div[j];
div[j] = t;
}
if(div[i] == div[j] && v[i] > v[j]) //if the number of divisors are the same
{
int t = v[i];
v[i] = v[j];
v[j] = t;
}
}
}
for(i = 0; i < n; i++)
{
cout << v[i] << " ";
}
return 0;
}
In.txt:
5
12 20 4 100 13
Output:
100 12 20 4 13
Although it works fine with this one and many other. For bigger inputs it exceeds the time limit which is 0.1s. Any advice how should I rewrite the sorting? (I wrote bubble sort because I could not implement sorting array by property via quicksort)
Use an array of structures. The structure would contain the original value and a container of divisors:
struct Number_Attributes
{
int number;
std::list<int> divisors;
};
You can then write a custom comparator function and pass to std::sort:
bool Order_By_Divisors(const Number_Attributes& a,
const Number_Attributes& b)
{
return a.divisors.size() < b.divisors.size();
}
The sorting then becomes:
#define ARRAY_CAPACITY (20U)
Number_Attributes the_array[ARRAY_CAPACITY];
//...
std::sort(&array[0], &array[ARRAY_CAPACITY], Order_By_Divisors);
The generation of divisors is left as an exercise for the OP.
Reworking your code with std::sort:
std::vector<std::pair<int, int>> customSort(const std::vector<int>& v)
{
std::vector<std::pair<int, int>> ps;
ps.reserve(v.size());
// We don't have zip sort :/
// So building the pair
for (auto e : v)
{
ps.emplace_back(e, cntDiv(e));
}
std::sort(ps.begin(), ps.end(), [](const auto&lhs, const auto& rhs) {
// descending number of divisors, increasing value
return std::make_tuple(-lhs.second, lhs.first)
< std::make_tuple(-rhs.second, rhs.first);
});
return ps;
}
int main()
{
const std::vector<int> v = {12, 20, 4, 100, 13};
const auto res = customSort(v);
for(const auto& p : res)
{
std::cout << p.first << " ";
}
}
Demo

Solving 5SUM in O(n^3) with strict memory limits

I need a way to solve the classic 5SUM problem without hashing or with a memory efficient way of hashing.
The problem asks you to find how many subsequences in a given array of length N have the sum equal to S
Ex:
Input
6 5
1 1 1 1 1 1
Output
6
The restrictions are:
N <= 1000 ( size of the array )
S <= 400000000 ( the sum of the subsequence )
Memory usage <= 5555 kbs
Execution time 2.2s
I'm pretty sure the excepted complexity is O(N^3). Due to the memory limitations hashing doesn't provide an actual O(1) time.
The best I got was 70 points using this code. ( I got TLE on 6 tests )
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#define MAX 1003
#define MOD 10472
using namespace std;
ifstream in("take5.in");
ofstream out("take5.out");
vector<pair<int, int>> has[MOD];
int v[MAX];
int pnt;
vector<pair<int, int>>::iterator it;
inline void ins(int val) {
pnt = val%MOD;
it = lower_bound(has[pnt].begin(), has[pnt].end(), make_pair(val, -1));
if(it == has[pnt].end() || it->first != val) {
has[pnt].push_back({val, 1});
sort(has[pnt].begin(), has[pnt].end());
return;
}
it->second++;
}
inline int get(int val) {
pnt = val%MOD;
it = lower_bound(has[pnt].begin(), has[pnt].end(), make_pair(val, -1));
if(it == has[pnt].end() || it->first != val)
return 0;
return it->second;
}
int main() {
int n,S;
int ach = 0;
int am = 0;
int rez = 0;
in >> n >> S;
for(int i = 1; i <= n; i++)
in >> v[i];
sort(v+1, v+n+1);
for(int i = n; i >= 1; i--) {
if(v[i] > S)
continue;
for(int j = i+1; j <= n; j++) {
if(v[i]+v[j] > S)
break;
ins(v[i]+v[j]);
}
int I = i-1;
if(S-v[I] < 0)
continue;
for(int j = 1; j <= I-1; j++) {
if(S-v[I]-v[j] < 0)
break;
for(int k = 1; k <= j-1; k++) {
if(S-v[I]-v[j]-v[k] < 0)
break;
ach = S-v[I]-v[j]-v[k];
rez += get(ach);
}
}
}
out << rez << '\n';
return 0;
}
I think it can be done. We are looking for all subsets of 5 items in the array arr with the correct SUM. We have array with indexes 0..N-1. Third item of those five can have index i in range 2..N-3. We cycle through all those indexes. For every index i we generate all combinations of two numbers for index in range 0..i-1 on the left of index i and all combinations of two numbers for index in the range i+1..N-1 on the right of index i. For every index i there are less than N*N combinations on the left plus on the right side. We would store only sum for every combination, so it would not be more than 1000 * 1000 * 4 = 4MB.
Now we have two sequences of numbers (the sums) and task is this: Take one number from first sequence and one number from second sequence and get sum equal to Si = SUM - arr[i]. How many combinations are there? To do it efficiently, sequences have to be sorted. Say first is sorted ascending and have numbers a, a, a, b, c ,.... Second is sorted descending and have numbers Z, Z, Y, X, W, .... If a + Z > Si then we can throw Z away, because we do not have smaller number to match. If a + Z < Si we can throw away a, because we do not have bigger number to match. And if a + Z = Si we have 2 * 3 = 6 new combinations and get rid of both a and Z. If we get sorting for free, it is nice O(N^3) algorithm.
While sorting is not for free, it is O(N * N^2 * log(N^2)) = O(N^3 * log(N)). We need to do sorting in linear time, which is not possible. Or is it? In index i+1 we can reuse sequences from index i. There are only few new combinations for i+1 - only those that involve number arr[i] together with some number from index 0..i-1. If we sort them (and we can, because there are not N*N of them, but N at most), all we need is to merge two sorted sequences. And that can be done in linear time. We can even avoid sorting completely if we sort arr at the beginning. We just merge.
For second sequence the merging does not involve adding but removing, but it is very simmilar.
The implementation seems to work, but I expect there is off by one error somewhere ;-)
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
int Generate(int arr[], int i, int sums[], int N, int NN)
{
int p1 = 0;
for (int i1 = 0; i1 < i - 1; ++i1)
{
int ai = arr[i1];
for (int i2 = i1 + 1; i2 < i; ++i2)
{
sums[p1++] = ai + arr[i2];
}
}
sort(sums, sums + p1);
return p1;
}
int Combinations(int n, int sums[], int p1, int p2, int NN)
{
int cnt = 0;
int a = 0;
int b = NN - p2;
do
{
int state = sums[a] + sums[b] - n;
if (state > 0) { ++b; }
else if (state < 0) { ++a; }
else
{
int cnta = 0;
int lastA = sums[a];
while (a < p1 && sums[a] == lastA) { a++; cnta++; }
int cntb = 0;
int lastB = sums[b];
while (b < NN && sums[b] == lastB) { b++; cntb++; }
cnt += cnta * cntb;
}
} while (b < NN && a < p1);
return cnt;
}
int Add(int arr[], int i, int sums[], int p2, int N, int NN)
{
int ii = N - 1;
int n = arr[i];
int nn = n + arr[ii--];
int ip = NN - p2;
int newP2 = p2 + N - i - 1;
for (int p = NN - newP2; p < NN; ++p)
{
if (ip < NN && (ii < i || sums[ip] > nn))
{
sums[p] = sums[ip++];
}
else
{
sums[p] = nn;
nn = n + arr[ii--];
}
}
return newP2;
}
int Remove(int arr[], int i, int sums[], int p1)
{
int ii = 0;
int n = arr[i];
int nn = n + arr[ii++];
int pp = 0;
int p = 0;
for (; p < p1 - i; ++p)
{
while (ii <= i && sums[pp] == nn)
{
++pp;
nn = n + arr[ii++];
}
sums[p] = sums[pp++];
}
return p;
}
int main() {
ifstream in("take5.in");
ofstream out("take5.out");
int N, SUM;
in >> N >> SUM;
int* arr = new int[N];
for (int i = 0; i < N; i++)
in >> arr[i];
sort(arr, arr + N);
int NN = (N - 3) * (N - 4) / 2 + 1;
int* sums = new int[NN];
int combinations = 0;
int p1 = 0;
int p2 = 1;
for (int i = N - 3; i >= 2; --i)
{
if (p1 == 0)
{
p1 = Generate(arr, i, sums, N, NN);
sums[NN - 1] = arr[N - 1] + arr[N - 2];
}
else
{
p1 = Remove(arr, i, sums, p1);
p2 = Add(arr, i + 1, sums, p2, N, NN);
}
combinations += Combinations(SUM - arr[i], sums, p1, p2, NN);
}
out << combinations << '\n';
return 0;
}

Algorithm to compute mode

I'm trying to devise an algorithm in the form of a function that accepts two parameters, an array and the size of the array. I want it to return the mode of the array and if there are multiple modes, return their average. My strategy was to take the array and first sort it. Then count all the occurrences of a number. while that number is occurring, add one to counter and store that count in an array m. So m is holding all the counts and another array q is holding the last value we were comparing.
For example: is my list is {1, 1, 1, 1, 2, 2, 2}
then i would have m[0] = 4 q[0] = 1
and then m[1] = 3 and q[1] = 2.
so the mode is q[0] = 1;
unfortunately i have had no success thus far. hoping someone could help.
float mode(int x[],int n)
{
//Copy array and sort it
int y[n], temp, k = 0, counter = 0, m[n], q[n];
for(int i = 0; i < n; i++)
y[i] = x[i];
for(int pass = 0; pass < n - 1; pass++)
for(int pos = 0; pos < n; pos++)
if(y[pass] > y[pos]) {
temp = y[pass];
y[pass] = y[pos];
y[pos] = temp;
}
for(int i = 0; i < n;){
for(int j = 0; j < n; j++){
while(y[i] == y[j]) {
counter++;
i++;
}
}
m[k] = counter;
q[k] = y[i];
i--; //i should be 1 less since it is referring to an array subscript
k++;
counter = 0;
}
}
Even though you have some good answers already, I decided to post another. I'm not sure it really adds a lot that's new, but I'm not at all sure it doesn't either. If nothing else, I'm pretty sure it uses more standard headers than any of the other answers. :-)
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <map>
#include <iostream>
#include <utility>
#include <functional>
#include <numeric>
int main() {
std::vector<int> inputs{ 1, 1, 1, 1, 2, 2, 2 };
std::unordered_map<int, size_t> counts;
for (int i : inputs)
++counts[i];
std::multimap<size_t, int, std::greater<size_t> > inv;
for (auto p : counts)
inv.insert(std::make_pair(p.second, p.first));
auto e = inv.upper_bound(inv.begin()->first);
double sum = std::accumulate(inv.begin(),
e,
0.0,
[](double a, std::pair<size_t, int> const &b) {return a + b.second; });
std::cout << sum / std::distance(inv.begin(), e);
}
Compared to #Dietmar's answer, this should be faster if you have a lot of repetition in the numbers, but his will probably be faster if the numbers are mostly unique.
Based on the comment, it seems you need to find the values which occur most often and if there are multiple values occurring the same amount of times, you need to produce the average of these. It seems, this can easily be done by std::sort() following by a traversal finding where values change and keeping a few running counts:
template <int Size>
double mode(int const (&x)[Size]) {
std::vector<int> tmp(x, x + Size);
std::sort(tmp.begin(), tmp.end());
int size(0); // size of the largest set so far
int count(0); // number of largest sets
double sum(0); // sum of largest sets
for (auto it(tmp.begin()); it != tmp.end(); ) {
auto end(std::upper_bound(it, tmp.end(), *it));
if (size == std::distance(it, end)) {
sum += *it;
++count;
}
else if (size < std::distance(it, end)) {
size = std::distance(it, end);
sum = *it;
count = 1;
}
it = end;
}
return sum / count;
}
If you simply wish to count the number of occurences then I suggest you use a std::map or std::unordered_map.
If you're mapping a counter to each distinct value then it's an easy task to count occurences using std::map as each key can only be inserted once. To list the distinct numbers in your list simply iterate over the map.
Here's an example of how you could do it:
#include <cstddef>
#include <map>
#include <algorithm>
#include <iostream>
std::map<int, int> getOccurences(const int arr[], const std::size_t len) {
std::map<int, int> m;
for (std::size_t i = 0; i != len; ++i) {
m[arr[i]]++;
}
return m;
}
int main() {
int list[7]{1, 1, 1, 1, 2, 2, 2};
auto occurences = getOccurences(list, 7);
for (auto e : occurences) {
std::cout << "Number " << e.first << " occurs ";
std::cout << e.second << " times" << std::endl;
}
auto average = std::accumulate(std::begin(list), std::end(list), 0.0) / 7;
std::cout << "Average is " << average << std::endl;
}
Output:
Number 1 occurs 4 times
Number 2 occurs 3 times
Average is 1.42857
Here's a working version of your code. m stores the values in the array and q stores their counts. At the end it runs through all the values to get the maximal count, the sum of the modes, and the number of distinct modes.
float mode(int x[],int n)
{
//Copy array and sort it
int y[n], temp, j = 0, k = 0, m[n], q[n];
for(int i = 0; i < n; i++)
y[i] = x[i];
for(int pass = 0; pass < n - 1; pass++)
for(int pos = 0; pos < n; pos++)
if(y[pass] > y[pos]) {
temp = y[pass];
y[pass] = y[pos];
y[pos] = temp;
}
for(int i = 0; i < n;){
j = i;
while (y[j] == y[i]) {
j++;
}
m[k] = y[i];
q[k] = j - i;
k++;
i = j;
}
int max = 0;
int modes_count = 0;
int modes_sum = 0;
for (int i=0; i < k; i++) {
if (q[i] > max) {
max = q[i];
modes_count = 1;
modes_sum = m[i];
} else if (q[i] == max) {
modes_count += 1;
modes_sum += m[i];
}
}
return modes_sum / modes_count;
}

Sieve of Eratosthenes algorithm

I am currently reading "Programming: Principles and Practice Using C++", in Chapter 4 there is an exercise in which:
I need to make a program to calculate prime numbers between 1 and 100 using the Sieve of Eratosthenes algorithm.
This is the program I came up with:
#include <vector>
#include <iostream>
using namespace std;
//finds prime numbers using Sieve of Eratosthenes algorithm
vector<int> calc_primes(const int max);
int main()
{
const int max = 100;
vector<int> primes = calc_primes(max);
for(int i = 0; i < primes.size(); i++)
{
if(primes[i] != 0)
cout<<primes[i]<<endl;
}
return 0;
}
vector<int> calc_primes(const int max)
{
vector<int> primes;
for(int i = 2; i < max; i++)
{
primes.push_back(i);
}
for(int i = 0; i < primes.size(); i++)
{
if(!(primes[i] % 2) && primes[i] != 2)
primes[i] = 0;
else if(!(primes[i] % 3) && primes[i] != 3)
primes[i]= 0;
else if(!(primes[i] % 5) && primes[i] != 5)
primes[i]= 0;
else if(!(primes[i] % 7) && primes[i] != 7)
primes[i]= 0;
}
return primes;
}
Not the best or fastest, but I am still early in the book and don't know much about C++.
Now the problem, until max is not bigger than 500 all the values print on the console, if max > 500 not everything gets printed.
Am I doing something wrong?
P.S.: Also any constructive criticism would be greatly appreciated.
I have no idea why you're not getting all the output, as it looks like you should get everything. What output are you missing?
The sieve is implemented wrongly. Something like
vector<int> sieve;
vector<int> primes;
for (int i = 1; i < max + 1; ++i)
sieve.push_back(i); // you'll learn more efficient ways to handle this later
sieve[0]=0;
for (int i = 2; i < max + 1; ++i) { // there are lots of brace styles, this is mine
if (sieve[i-1] != 0) {
primes.push_back(sieve[i-1]);
for (int j = 2 * sieve[i-1]; j < max + 1; j += sieve[i-1]) {
sieve[j-1] = 0;
}
}
}
would implement the sieve. (Code above written off the top of my head; not guaranteed to work or even compile. I don't think it's got anything not covered by the end of chapter 4.)
Return primes as usual, and print out the entire contents.
Think of the sieve as a set.
Go through the set in order. For each value in thesive remove all numbers that are divisable by it.
#include <set>
#include <algorithm>
#include <iterator>
#include <iostream>
typedef std::set<int> Sieve;
int main()
{
static int const max = 100;
Sieve sieve;
for(int loop=2;loop < max;++loop)
{
sieve.insert(loop);
}
// A set is ordered.
// So going from beginning to end will give all the values in order.
for(Sieve::iterator loop = sieve.begin();loop != sieve.end();++loop)
{
// prime is the next item in the set
// It has not been deleted so it must be prime.
int prime = *loop;
// deleter will iterate over all the items from
// here to the end of the sieve and remove any
// that are divisable be this prime.
Sieve::iterator deleter = loop;
++deleter;
while(deleter != sieve.end())
{
if (((*deleter) % prime) == 0)
{
// If it is exactly divasable then it is not a prime
// So delete it from the sieve. Note the use of post
// increment here. This increments deleter but returns
// the old value to be used in the erase method.
sieve.erase(deleter++);
}
else
{
// Otherwise just increment the deleter.
++deleter;
}
}
}
// This copies all the values left in the sieve to the output.
// i.e. It prints all the primes.
std::copy(sieve.begin(),sieve.end(),std::ostream_iterator<int>(std::cout,"\n"));
}
From Algorithms and Data Structures:
void runEratosthenesSieve(int upperBound) {
int upperBoundSquareRoot = (int)sqrt((double)upperBound);
bool *isComposite = new bool[upperBound + 1];
memset(isComposite, 0, sizeof(bool) * (upperBound + 1));
for (int m = 2; m <= upperBoundSquareRoot; m++) {
if (!isComposite[m]) {
cout << m << " ";
for (int k = m * m; k <= upperBound; k += m)
isComposite[k] = true;
}
}
for (int m = upperBoundSquareRoot; m <= upperBound; m++)
if (!isComposite[m])
cout << m << " ";
delete [] isComposite;
}
Interestingly, nobody seems to have answered your question about the output problem. I don't see anything in the code that should effect the output depending on the value of max.
For what it's worth, on my Mac, I get all the output. It's wrong of course, since the algorithm isn't correct, but I do get all the output. You don't mention what platform you're running on, which might be useful if you continue to have output problems.
Here's a version of your code, minimally modified to follow the actual Sieve algorithm.
#include <vector>
#include <iostream>
using namespace std;
//finds prime numbers using Sieve of Eratosthenes algorithm
vector<int> calc_primes(const int max);
int main()
{
const int max = 100;
vector<int> primes = calc_primes(max);
for(int i = 0; i < primes.size(); i++)
{
if(primes[i] != 0)
cout<<primes[i]<<endl;
}
return 0;
}
vector<int> calc_primes(const int max)
{
vector<int> primes;
// fill vector with candidates
for(int i = 2; i < max; i++)
{
primes.push_back(i);
}
// for each value in the vector...
for(int i = 0; i < primes.size(); i++)
{
//get the value
int v = primes[i];
if (v!=0) {
//remove all multiples of the value
int x = i+v;
while(x < primes.size()) {
primes[x]=0;
x = x+v;
}
}
}
return primes;
}
In the code fragment below, the numbers are filtered before they are inserted into the vector. The divisors come from the vector.
I'm also passing the vector by reference. This means that the huge vector won't be copied from the function to the caller. (Large chunks of memory take long times to copy)
vector<unsigned int> primes;
void calc_primes(vector<unsigned int>& primes, const unsigned int MAX)
{
// If MAX is less than 2, return an empty vector
// because 2 is the first prime and can't be placed in the vector.
if (MAX < 2)
{
return;
}
// 2 is the initial and unusual prime, so enter it without calculations.
primes.push_back(2);
for (unsigned int number = 3; number < MAX; number += 2)
{
bool is_prime = true;
for (unsigned int index = 0; index < primes.size(); ++index)
{
if ((number % primes[k]) == 0)
{
is_prime = false;
break;
}
}
if (is_prime)
{
primes.push_back(number);
}
}
}
This not the most efficient algorithm, but it follows the Sieve algorithm.
below is my version which basically uses a bit vector of bool and then goes through the odd numbers and a fast add to find multiples to set to false. In the end a vector is constructed and returned to the client of the prime values.
std::vector<int> getSieveOfEratosthenes ( int max )
{
std::vector<bool> primes(max, true);
int sz = primes.size();
for ( int i = 3; i < sz ; i+=2 )
if ( primes[i] )
for ( int j = i * i; j < sz; j+=i)
primes[j] = false;
std::vector<int> ret;
ret.reserve(primes.size());
ret.push_back(2);
for ( int i = 3; i < sz; i+=2 )
if ( primes[i] )
ret.push_back(i);
return ret;
}
Here is a concise, well explained implementation using bool type:
#include <iostream>
#include <cmath>
void find_primes(bool[], unsigned int);
void print_primes(bool [], unsigned int);
//=========================================================================
int main()
{
const unsigned int max = 100;
bool sieve[max];
find_primes(sieve, max);
print_primes(sieve, max);
}
//=========================================================================
/*
Function: find_primes()
Use: find_primes(bool_array, size_of_array);
It marks all the prime numbers till the
number: size_of_array, in the form of the
indexes of the array with value: true.
It implemenets the Sieve of Eratosthenes,
consisted of:
a loop through the first "sqrt(size_of_array)"
numbers starting from the first prime (2).
a loop through all the indexes < size_of_array,
marking the ones satisfying the relation i^2 + n * i
as false, i.e. composite numbers, where i - known prime
number starting from 2.
*/
void find_primes(bool sieve[], unsigned int size)
{
// by definition 0 and 1 are not prime numbers
sieve[0] = false;
sieve[1] = false;
// all numbers <= max are potential candidates for primes
for (unsigned int i = 2; i <= size; ++i)
{
sieve[i] = true;
}
// loop through the first prime numbers < sqrt(max) (suggested by the algorithm)
unsigned int first_prime = 2;
for (unsigned int i = first_prime; i <= std::sqrt(double(size)); ++i)
{
// find multiples of primes till < max
if (sieve[i] = true)
{
// mark as composite: i^2 + n * i
for (unsigned int j = i * i; j <= size; j += i)
{
sieve[j] = false;
}
}
}
}
/*
Function: print_primes()
Use: print_primes(bool_array, size_of_array);
It prints all the prime numbers,
i.e. the indexes with value: true.
*/
void print_primes(bool sieve[], unsigned int size)
{
// all the indexes of the array marked as true are primes
for (unsigned int i = 0; i <= size; ++i)
{
if (sieve[i] == true)
{
std::cout << i <<" ";
}
}
}
covering the array case. A std::vector implementation will include minor changes such as reducing the functions to one parameter, through which the vector is passed by reference and the loops will use the vector size() member function instead of the reduced parameter.
Here is a more efficient version for Sieve of Eratosthenes algorithm that I implemented.
#include <iostream>
#include <cmath>
#include <set>
using namespace std;
void sieve(int n){
set<int> primes;
primes.insert(2);
for(int i=3; i<=n ; i+=2){
primes.insert(i);
}
int p=*primes.begin();
cout<<p<<"\n";
primes.erase(p);
int maxRoot = sqrt(*(primes.rbegin()));
while(primes.size()>0){
if(p>maxRoot){
while(primes.size()>0){
p=*primes.begin();
cout<<p<<"\n";
primes.erase(p);
}
break;
}
int i=p*p;
int temp = (*(primes.rbegin()));
while(i<=temp){
primes.erase(i);
i+=p;
i+=p;
}
p=*primes.begin();
cout<<p<<"\n";
primes.erase(p);
}
}
int main(){
int n;
n = 1000000;
sieve(n);
return 0;
}
Here's my implementation not sure if 100% correct though :
http://pastebin.com/M2R2J72d
#include<iostream>
#include <stdlib.h>
using namespace std;
void listPrimes(int x);
int main() {
listPrimes(5000);
}
void listPrimes(int x) {
bool *not_prime = new bool[x];
unsigned j = 0, i = 0;
for (i = 0; i <= x; i++) {
if (i < 2) {
not_prime[i] = true;
} else if (i % 2 == 0 && i != 2) {
not_prime[i] = true;
}
}
while (j <= x) {
for (i = j; i <= x; i++) {
if (!not_prime[i]) {
j = i;
break;
}
}
for (i = (j * 2); i <= x; i += j) {
not_prime[i] = true;
}
j++;
}
for ( i = 0; i <= x; i++) {
if (!not_prime[i])
cout << i << ' ';
}
return;
}
I am following the same book now. I have come up with the following implementation of the algorithm.
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
inline void keep_window_open() { char ch; cin>>ch; }
int main ()
{
int max_no = 100;
vector <int> numbers (max_no - 1);
iota(numbers.begin(), numbers.end(), 2);
for (unsigned int ind = 0; ind < numbers.size(); ++ind)
{
for (unsigned int index = ind+1; index < numbers.size(); ++index)
{
if (numbers[index] % numbers[ind] == 0)
{
numbers.erase(numbers.begin() + index);
}
}
}
cout << "The primes are\n";
for (int primes: numbers)
{
cout << primes << '\n';
}
}
Here is my version:
#include "std_lib_facilities.h"
//helper function:check an int prime, x assumed positive.
bool check_prime(int x) {
bool check_result = true;
for (int i = 2; i < x; ++i){
if (x%i == 0){
check_result = false;
break;
}
}
return check_result;
}
//helper function:return the largest prime smaller than n(>=2).
int near_prime(int n) {
for (int i = n; i > 0; --i) {
if (check_prime(i)) { return i; break; }
}
}
vector<int> sieve_primes(int max_limit) {
vector<int> num;
vector<int> primes;
int stop = near_prime(max_limit);
for (int i = 2; i < max_limit+1; ++i) { num.push_back(i); }
int step = 2;
primes.push_back(2);
//stop when finding the last prime
while (step!=stop){
for (int i = step; i < max_limit+1; i+=step) {num[i-2] = 0; }
//the multiples set to 0, the first none zero element is a prime also step
for (int j = step; j < max_limit+1; ++j) {
if (num[j-2] != 0) { step = num[j-2]; break; }
}
primes.push_back(step);
}
return primes;
}
int main() {
int max_limit = 1000000;
vector<int> primes = sieve_primes(max_limit);
for (int i = 0; i < primes.size(); ++i) {
cout << primes[i] << ',';
}
}
Here is a classic method for doing this,
int main()
{
int max = 500;
vector<int> array(max); // vector of max numbers, initialized to default value 0
for (int i = 2; i < array.size(); ++ i) // loop for rang of numbers from 2 to max
{
// initialize j as a composite number; increment in consecutive composite numbers
for (int j = i * i; j < array.size(); j +=i)
array[j] = 1; // assign j to array[index] with value 1
}
for (int i = 2; i < array.size(); ++ i) // loop for rang of numbers from 2 to max
if (array[i] == 0) // array[index] with value 0 is a prime number
cout << i << '\n'; // get array[index] with value 0
return 0;
}
I think im late to this party but im reading the same book as you, this is the solution in came up with! Feel free to make suggestions (you or any!), for what im seeing here a couple of us extracted the operation to know if a number is multiple of another to a function.
#include "../../std_lib_facilities.h"
bool numIsMultipleOf(int n, int m) {
return n%m == 0;
}
int main() {
vector<int> rawCollection = {};
vector<int> numsToCheck = {2,3,5,7};
// Prepare raw collection
for (int i=2;i<=100;++i) {
rawCollection.push_back(i);
}
// Check multiples
for (int m: numsToCheck) {
vector<int> _temp = {};
for (int n: rawCollection) {
if (!numIsMultipleOf(n,m)||n==m) _temp.push_back(n);
}
rawCollection = _temp;
}
for (int p: rawCollection) {
cout<<"N("<<p<<")"<<" is prime.\n";
}
return 0;
}
Try this code it will be useful to you by using java question bank
import java.io.*;
class Sieve
{
public static void main(String[] args) throws IOException
{
int n = 0, primeCounter = 0;
double sqrt = 0;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println(“Enter the n value : ”);
n = Integer.parseInt(br.readLine());
sqrt = Math.sqrt(n);
boolean[] prime = new boolean[n];
System.out.println(“\n\nThe primes upto ” + n + ” are : ”);
for (int i = 2; i<n; i++)
{
prime[i] = true;
}
for (int i = 2; i <= sqrt; i++)
{
for (int j = i * 2; j<n; j += i)
{
prime[j] = false;
}
}
for (int i = 0; i<prime.length; i++)
{
if (prime[i])
{
primeCounter++;
System.out.print(i + ” “);
}
}
prime = new boolean[0];
}
}