I am trying to make a program that calculates the amount of prime numbers that don't exceed an integer using the sieve of Eratosthenes. While my program works fine (and fast) for small numbers, after a certain number (46337) I get a "command terminated by signal 11" error, which I suppose has to do with array size. I tried to use malloc() but I didn't get it quite right. What shall I do for big numbers (up to 5billion)?
#include <stdio.h>
#include<stdlib.h>
int main(){
signed long int x,i, j, prime = 0;
scanf("%ld", &x);
int num[x];
for(i=2; i<=x;i++){
num[i]=1;
}
for(i=2; i<=x;i++){
if(num[i] == 1){
for(j=i*i; j<=x; j = j + i){
num[j] = 0;
}
//printf("num[%d]\n", i);
prime++;
}
}
printf("%ld", prime);
return 0;
}
Your array
int num[x];
is on the stack, where only small arrays can be accommodated. For large array size you'll have to allocate memory. You can save on memory bloat by using char type, because you only need a status.
char *num = malloc(x+1); // allow for indexing by [x]
if(num == NULL) {
// deal with allocation error
}
//... the sieve code
free(num);
I suggest also, you must check that i*i does not break the int limit by using
if(num[i] == 1){
if (x / i >= i){ // make sure i*i won't break
for(j=i*i; j<=x; j = j + i){
num[j] = 0;
}
}
}
Lastly, you want to go to 5 billion, which is outside the range of uint32_t (which unsigned long int is on my system) at 4.2 billion. If that will satisfy you, change the int definitions to unsigned, watching out that your loop controls don't wrap, that is, use unsigned x = UINT_MAX - 1;
If you don't have 5Gb memory available, use bit status as suggest by #BoPersson.
The following code checks for errors, tested with values up to 5000000000, properly outputs the final count of number of primes, uses malloc so as to avoid overrunning the available stack space.
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long int x,i, j;
unsigned prime = 0;
scanf("%lu", &x);
char *num = malloc( x);
if( NULL == num)
{
perror( "malloc failed");
exit(EXIT_FAILURE);
}
for(i=0; i<x;i++)
{
num[i]=1;
}
for(i=2; i<x;i++)
{
if(num[i] == 1)
{
for(j=i*i; j<x; j = j + i)
{
num[j] = 0;
}
//printf("num[%lu]\n", i);
prime++;
}
}
printf("%u\n", prime);
return 0;
}
Related
I'm currently learning C and have been practicing on codewars recently. I came across this question on prime gaps and was curious on how to improve it. I was initially fooled in thinking this wouldn't be as bad but I realized that finding primes is difficult (especially for large numbers where it can be at least an NP-Hard problem). I know my code right now has multiple for-loops and this is terrible in terms of performance. I also don't fully know the clean ways of writing C so there might be some no-nos I did (e.g. I know it's my responsibility to free up dynamically allocated memory but I tried freeing memory in the main() calling function and by freeing the first element of the allocated memory block--not sure if this is the appropriate way of freeing up a block of memory)
In general, the main function calls the prime_gap function several times. I know this code works because it was submitted successfully but any tips on writing this better (algorithmically in C)?
/* a prime gap of length "n" indicates that n-1 consecutive composite numbers exist between two primes.
* For example, the gap beween (2,3) is 1, the gap between (5,7) is 2 and the gap between (7,11) is 4.
* Our function should return the first pair of primes that satisfies the gap that we're looking for in a search between two numbers. /
There should also be no primes that exist within the gap of the first two primes that are found.
* gap(g, n, m) -> where g = gap length, n = start of search space, m = end of search space
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
long long *gap(int g, int n, int m);
bool check_prime(int, bool);
int main(int argc, const char *argv[]){
long long *check3 = gap(2,100,110);
for (int i = 0; i < 2; i++){
printf("%lld ", check3[i]);
}
free(&check3[0]);
printf("\n");
long long *check = gap(2,3,50);
for (int i = 0; i< 2; i++){
printf("%lld ", check[i]);
}
printf("\n");
free(&check[0]);
long long *check1 = gap(2,5,5);
for (int i = 0; i < 2; i++){
printf("%lld ", check1[i]);
}
free(&check1[0]);
printf("\n");
long long *check2 = gap(4,130,200);
for (int i = 0; i < 2; i++){
printf("%lld ", check2[i]);
}
free(&check2[0]);
printf("\n");
long long *check4 = gap(6,100,110);
for (int i = 0; i < 2; i++){
printf("%lld ", check4[i]);
}
free(&check4[0]);
printf("\n");
long long *gap(int g, int n, int m) {
long long *result = (long long*) malloc(sizeof(long long) *2); // dynamically allocate 2 long longs for the integer array
if (result == NULL){
perror("Not enough memory");
}
int test = 0;
static bool prime;
for (int i = n; i < m; i++) { // traverse search space
prime = true;
prime = check_prime(i, prime);
if (prime == true) { // identifies prime number
test = i + g; // add the gap value to identified prime
prime = false; // set bool to false to now check for any primes that exist between i and i+gap
for (int z = i+1; z < test; z++ ) { // check there is no prime in between the first and second (test) primes
prime = check_prime(z, prime);
if (prime == true) break;
}
if (prime != true) { // found no primes between i and i+gap
prime = true; // set bool to true to then toggle off in the check right below if i+gap is not actually prime
prime = check_prime(test, prime); // now need to check whether i+gap itself is a prime
if (prime == true) {
result[0] = i; result[1] = test;
return result;
}
}
}
}
result[0] = result[1] = 0;
return result;
}
bool check_prime(int i, bool prime){
for (int j = 2; j <= sqrt(i); j++){
if (i % j == 0) {
return false;
}
}
return true;
}
Reading you code, the following comments come to mind:
you are never freeing the space allocated by the malloc
therefore I am wondering if you really need to use malloc, a simple global variable would have been sufficient for what you are doing with it
you check_prime function has a second parameter prime that is never used
in function gap, the variable prime is indicated as static, this is not required, it could also lead to errors
from the algorithmic point of view:
your logic goes like
for i in range to check:
if i is prime
check if all the number between i and i+gap are not prime
if i+gap is prime then return the tuple(i, i+gap)
globally, you are checking several times for the same number if it is prime, since this is by far the most "expensive" operation, you should try not to
specifically, you should start by checking test before iterating over all the numbers in the range i..test.
Adding the printf("Hi!\n") statements allows the code to work. It also works if the bound initial bound is improper and the user enters a new one. When I ran some tests calculate divers sometimes returned a character instead of an integer. I'm thinking it has something to do with my memory allocation. I also noticed that ./a.out 6 10 "|" would work but ./a.out 6 25 "|" would not causing an infinite loop when printing the lines of "|".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Structs
typedef struct data_struct {
int lineNumber;
int divisorSum;
char type[10];
}data;
// Prototypes
int calculateDivsors(int integer);
// Functions
int main (int argc, char *argv[]) {
int lowerBound;
int upperBound;
char character;
// Gets the values from command-line
sscanf(argv[1], "%d", &lowerBound);
sscanf(argv[2], "%d", &upperBound);
sscanf(argv[3], "%c", &character);
// Check to see if bound is proper
while (upperBound <= lowerBound || lowerBound < 2) {
printf("Error, please enter a new range (positive increasing).\n");
scanf("%d %d", &lowerBound, &upperBound);
}
// Structure calls
data* info = NULL;
int totalData = upperBound - lowerBound;
// Allocate the memory
info = (data*)malloc(totalData * sizeof(data));
printf("Hi!\n");
if (info != NULL) {
// Iterate through all the digits between the two bounds
for (int i = lowerBound; i <= upperBound; i++) {
int sum = calculateDivsors(i);
// Write data to indiviual structures
info[i].lineNumber = i;
info[i].divisorSum = sum;
// Check to see if the sum is greater than, less than, or equal to the original
if (sum == i) {
strcpy(info[i].type, "Perfect");
}
else if (sum > i) {
strcpy(info[i].type, "Abundant");
}
else if (sum < i) {
strcpy(info[i].type, "Deficient");
}
// Line n# has a column width of 4, string of 10
printf("%4d is %-10s\t", info[i].lineNumber, info[i].type);
// Generate Pictogram
for (int j = 0; j < info[i].divisorSum; j++) {
printf("%c", character);
}
printf("\n");
}
}
}
// Adds up the sum of diviors
int calculateDivsors(int integer) {
int sum = 0;
for (int i = 1; i < integer; i++) {
// Add to sum if perfectly i is a sum of integer
if (integer % i == 0) {
sum += i;
}
}
return sum; // Returns the sum of diviors
}
You are accessing data outside its allocated buffer whenever lowerBound doesn't start with 0.
info[i].lineNumber = i;
Ideally, you should become...
info[i - lowerBound].lineNumber = i;
To ensure that the indexing starts at 0. Further, your window between lowerBound and upperBound is inclusive. That means it includes both ending boundaries. Therefore, totalData is undersized by one element. Even if you fix the indexing problem, your code will still be wrong with this:
int totalData = (upperBound - lowerBound) + 1;
Failing to do both of the above causes your code to invoke undefined behavior (UB), and thus unpredictable results thereafter. It may even appear to work. That, however, is a red herring when your code has UB. Don't confuse defined behavior with observed behavior. You can trust the latter only once you have the former; the two are not synonymous.
I am trying to find the number of distinct numbers from input which are not equal to 0. n is in 1-100 range. The numbers in the array are in the 0-600 range.
http://codeforces.com/problemset/problem/937/A
For this question, I wrote a code:
#include <stdio.h>
#include <string.h>
int main(void)
{
int n, count = 0, i;
scanf("%d", &n);
int ar[n], ar2[601];
memset(ar2, 0, 600 * sizeof(int));
for (i = 0; i < n; i++) {
scanf("%d ", &ar[i]);
if (ar2[ar[i]] == 0)
ar2[ar[i]] = 1;
}
for (i = 1; i < 601; i++) {
if (ar2[i] != 0)
count++;
}
printf("%d",count);
return 0;
}
for the first test case (4 1 3 3 2) , it outputs the right answer 3 in ideone.com 's gcc 6.3, but outputs 4 in gcc 5.1 which is used at codeforces.
Why does this happen, and how can I prevent this ?
(I think it's because of memset, but I'm not sure.)
You are defining an array of size n before the value of n has beed determined (note that you scanf the value of n later). This is undefined behaviour, such that different compilers may give different results, and even starting your program on your machine may give different results (including crashes).
instead of
int n, count = 0, i;
int ar[n];
...
write
int n, count = 0, i;
scanf("%d", &n);
int ar[n], ar2[601] = { 0 };
At least the malformed array should then be solved, and ar2 is completely initialized with 0. You can get rid of your memset, which initialized only 600 items (instead of 601) anyway.
Here is a quicker solution to the problem
#include <stdio.h>
int main()
{
bool seen_number_before[601] = { false };
int count = 0;
seen_number_before[0] = true;
int n;
scanf("%d", &n); // Should do error checking here
for (int i = 0; i < n; ++i) {
int v;
scanf("%d", v); // More error checking
if (!seen_number_before[v]) // Not seen it before
seen_number_before[v] = true; // Mark it as seen
++count; // Add to the count
}
}
printf("%d\n", count);
return 0;
}
}
There are some errors in your code, from a[n] when n is not defined.
To check errors try compiling with some useful options:
gcc -Wall code.c -o code -g
the -Wall is for Warning all and the -g is used for debug on valgrind (useful tool to check memory leak and other errors).
Also I suggest you to name properly every var in your code, could helpful for a large size of code base.
This is my solution,
#include <stdio.h>
#include <stdlib.h>
int main(){
int n, count = 0;
scanf("%d", &n);
int *a = malloc(n * sizeof(int));
int hash[600] = { 0 };
for(int i=0; i<n; i++){
scanf("%d ", &a[i]);
if(a[i] != 0){
hash[a[i]] = 1;
}
}
for(int i=0; i<600; i++){
printf("%d ", hash[i]);
if(hash[i] == 1) ++count;
}
printf("\n\n%d\n", count);
return 0;
}
it can be optimized in time, using only one for, and/or in memory by creating an hashset of int, and every int can store 32 bit and do some bitwise operations, so if the nth bit is 1, count++, otherwise don't do nothing.
i got a problem which i can't solve
I want to know all prime numbers below a given limit x. Allowing me to enter x and calculate the prime numbers using the method of Erastosthenes. Displaying the result on the screen and saving it to a text file.
Calculating the primenumbers below the x, printing them and saving them to a text file worked, the only problem i have is that x can't exceed 500000
could you guys help me?
#include <stdio.h>
#include <math.h>
void sieve(long x, int primes[]);
main()
{
long i;
long x=500000;
int v[x];
printf("give a x\n");
scanf("%d",&x);
FILE *fp;
fp = fopen("primes.txt", "w");
sieve(x, v);
for (i=0;i<x;i++)
{
if (v[i] == 1)
{
printf("\n%d",i);
fprintf(fp, "%d\n",i);
}
}
fclose(fp);
}
void sieve(long x, int primes[])
{
int i;
int j;
for (i=0;i<x;i++)
{
primes[i]=1; // we initialize the sieve list to all 1's (True)
primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}
for (i=2;i<sqrt(x);i++) // loop through all the numbers up to the sqrt(n)
{
for (j=i*i;j<x;j+=i) // mark off each factor of i by setting it to 0 (False)
{
primes[j] = 0;
}
}
}
You will be able to handle four times as many values by declaring char v [500000] instead of int v [100000].
You can handle eight times more values by declaring unsigned char v [500000] and using only a single bit for each prime number. This makes the code a bit more complicated.
You can handle twice as many values by having a sieve for odd numbers only. Since 2 is the only even prime number, there is no point keeping them in the sieve.
Since memory for local variables in a function is often quite limited, you can handle many more values by using a static array.
Allocating v as an array of int is wasteful, and making it a local array is risky, stack space being limited. If the array becomes large enough to exceed available stack space, the program will invoke undefined behaviour and likely crash.
While there are ways to improve the efficiency of the sieve by changing the sieve array to an array of bits containing only odd numbers or fewer numbers (6n-1 and 6n+1 is a good trick), you can still improve the efficiency of your simplistic approach by a factor of 10 with easy changes:
fix primes[0] and primes[1] outside the loop,
clear even offsets of prime except the first and only scan odd numbers,
use integer arithmetic for the outer loop limit,
ignore numbers that are already known to be composite,
only check off odd multiples of i.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sieve(long x, unsigned char primes[]) {
long i, j;
for (i = 0; i < x; i++) {
primes[i] = i & 1;
}
primes[1] = 0;
primes[2] = 1;
/* loop through all odd numbers up to the sqrt(x) */
for (i = 3; (j = i * i) < x; i += 2) {
/* skip composite numbers */
if (primes[i] == 0)
continue;
/* mark each odd multiple of i as composite */
for (; j < x; j += i + i) {
primes[j] = 0;
}
}
}
int main(int argc, char *argv[]) {
long i, x, count;
int do_count = 0;
unsigned char *v;
if (argc > 1) {
x = strtol(argv[1], NULL, 0);
} else {
printf("enter x: ");
if (scanf("%ld", &x) != 1)
return 1;
}
if (x < 0) {
x = -x;
do_count = 1;
}
v = malloc(x);
if (v == NULL) {
printf("Not enough memory\n");
return 1;
}
sieve(x, v);
if (do_count) {
for (count = i = 0; i < x; i++) {
count += v[i];
}
printf("%ld\n", count);
} else {
for (i = 0; i < x; i++) {
if (v[i] == 1) {
printf("%ld\n", i);
}
}
}
free(v);
return 0;
}
I believe the problem you are having is allocating an array of int if more than 500000 elements on the stack. This is not an efficient way, to use an array where the element is the number and the value indicates whether it is prime or not. If you want to do this, at least use bool, not int as this should only be 1 byte, not 4.
Also notice this
for (i=0;i<x;i++)
{
primes[i]=1; // we initialize the sieve list to all 1's (True)
primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}
You are reassigning the first two elements in each loop. Take it out of the loop.
You are initializing x to be 500000, then creating an array with x elements, thus it will have 500000 elements. You are then reading in x. The array will not change size when the value of x changes - it is fixed at 500000 elements, the value of x when you created the array. You want something like this:
long x=500000;
printf("give a x\n");
scanf("%d",&x);
int *v = new int[x];
This fixes your fixed size array issue, and also gets it off the stack and into the heap which will allow you to allocate more space. It should work up to the limit of the memory you have available.
This question has been asked here on SO before with below code
find3missing(int* array)
{
int newarray[100] = {0};
For i = 0 to 99
++newarray[array[i]] ;
For i = 0 to 99
If newarray[i] != 1
Cout << “the missing number is ” << i+1 << endl ;
}
But when I checked this code, it doesn't seem to work. Suppose I have an array of {1,2,6}. The output should be 3,4,5 but with the code above I get 1,4,5,6 instead. Below is my implementation of pseudo code with array size 6.
main()
{
int a[6]={1,2,6};
int tmp[6]={0},i;
for(i=0;i<6;i++)
{
++tmp[a[i]];
}
for(i=0;i<6;i++)
{
if(tmp[i]!=1)
{
printf("%d",i+1);
}
}
}
Is this the right code?
This ++newarray[array[i]] should be ++newarray[array[i] - 1]. This because you are interested in a sequence of 1-100 numbers, so no 0, but C arrays are 0 based. If you then look at the cout: the missing number is ” << i+1 here you "unshift" the number by adding 1.
There is another problem: you should pass the number of elements of the array, something like:
find3missing(int* array, int length) {
int newarray[100] = {0};
for (int i = 0; i < length; i++) {
++newarray[array[i] - 1] ;
}
C/C++ arrays are zero based, as A[i] is equivalent to *(A+i). So change ++newarray[array[i]] to ++newarray[array[i]-1]. Also use malloc, free and memset to use an array of dynamic size.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void find3missing(int* pArray, size_t size, int min, int max){
int* newarray;
int i;
unsigned int j;
int range = max - min;
if(range < 0)
return;
newarray = (int*) malloc(range*sizeof(int)); // allocate enough memory
memset(newarray,0,range*sizeof(int)); // set that block to zero
for(j = 0; j < size; ++j){
++newarray[pArray[j]-min];
}
for(i = 0; i < range; ++i){
if(!newarray[i])
printf("%d is missing!\n",min+i);
}
free(newarray);
}
int main(){
int test[] = {1,3,6};
find3missing(test,sizeof(test)/sizeof(int),1,6);
return 0;
}
Please note that this solution is very inefficient if your array is sorted. In this case have a look at Jimmy Gustafsson's answer.
This algoritm will be quite simple, since you're using a sorted array. Simply check if the current value +1 equals the nextvalue like below:
find3missing(){
int array[arraySize]; // the array with integers
for(i=0;i<arraySize;i++)
if(array[i]+1 != array[i+1]) // if value array[i]+1 is not equal the next index
// value, then it's a missing number
printf("A missing number: %i", i+1);
}