Efficient algorithm for finding primes and adding them? [duplicate] - c

This question already has answers here:
Concurrent Prime Generator
(10 answers)
Closed 8 years ago.
For project euler Problem 10, we are supposed to add all primes but that is taking my computer years to do it. Need a more efficient algorithm!
Heres my present C code:
#include <stdio.h>
int main(void)
{
int i, j, flag, sum=0;
for(i=3; i< 2000000; i = i + 2)
{
flag=0;
for(j=3; j<=i/2; j = j + 2)
{
if(i%j==0)
{
flag=1;
break;
}
}
if(flag==0)
sum += i;
}
printf ("%i", sum + 2);
}

Here is a slight improvement to your procedure, while keeping the same algorithm for testing primality:
Set the sum variable to the sum of the first two primes (i.e., 2+3 = 5)
Start from 5, and test only numbers that are adjacent to multiples of 6
For each number, test it only with divisors that are adjacent to multiples of 6
For each number, test it only with divisors between 5 and the square root of the number
Please note that this implementation improves the performance of the algorithm but not the time-complexity of the algorithm, and that there are more efficient methods for testing primality.
int i, j, iplus, jplus, flag, iroot, sum = 2+3;
int iroot = (int)ceil(sqrt((float)5));
int square = iroot*iroot;
for (i=5, iplus=2; i<2000000; i+=iplus, iplus=4-iplus)
{
flag = 0;
if (square < i)
{
iroot++;
square = iroot*iroot;
// instead of calculating the square root of the number every time,
// calculate it at the beginning, and increment it only when needed
}
for (j=5, jplus=2; j<=iroot; j+=jplus, jplus=4-jplus)
{
if (i%j == 0)
{
flag = 1;
break;
}
}
if (flag == 0)
sum += i;
}
printf("%i", sum);

Related

Need to make code efficient and reduce time complexity

Given a range [ L , R ] (both inclusive), I have to tell find the maximum difference between two prime numbers in the given range. There are three answers possible for the given range.
If there is only one distinct prime number in the given range, then maximum difference in this case would be 0.
If there are no prime numbers in the given range, then output for this case would be -1.
Example:
Range: [ 1, 10 ]
The maximum difference between the prime numbers in the given range is 5.
Difference = 7 - 2 = 5
Range: [ 5, 5 ]
There is only one distinct prime number so the maximum difference would be 0.
Range: [ 8 , 10 ]
There is no prime number in the given range so the output for the given range would be -1.
Input Format
The first line of input consists of the number of test cases, T
Next T lines each consists of two space-separated integers, L and R
Constraints
1<= T <=10
2<= L<= R<=10^6
This is my code:
#include <stdio.h>
int isprime(int n)
{
int i,c=0;
for(i=1;i<n;i++)
{
if(n%i==0)
c++;
}
if(c==1)
return 1;
else
return 0;
}
int main()
{
int t; //testnumber
scanf("%d",&t);
for(int k=0;k<t;k++)
{
int l,r; //l=low or floor, r = highest range or ceiling;[l,r]
scanf("%d%d",&l,&r);
int n = r-l; //difference in range
int a[n];
int j=0;
for(int i=l;i<=r;i++)
{
if(isprime(i)==1)
{
a[j] = i;
j++;
}
}
int d = a[j-1]-a[0];
if(j==0)
printf("%d\n",-1);
else
printf("%d\n",d);
}
return 0;
}
When posting on a forum/stack or asking for review, try to name your variables appropriately. Otherwise, it becomes uneasy to follow the code or what is the purpose of which variable.
I wrote the code below hoping you will understand my implementation.
#include <iostream>
#include <math.h>
using namespace std;
void isPrime(int num, int* primeNumber)
{
if (num == 2)
{
*primeNumber = num; //2 is a prime number
return;
}
if (num%2 == 0)
{
return; //num is an even number, so, not prime
}
int limit = sqrt(num);
if (limit*limit == num)
{
return; //num is a square number, so, not prime
}
for (int i = 3; i <= limit; i=i+2)//to find if a number is prime or not, we only have to divide it from 2 to sqrt(num).
{ //i=i+2 skips even number, cause already checked if num is even or not.
if (num % i == 0)
{
return; //`num` is divisible by i, so, not prime
}
}
*primeNumber = num; //no divisible number found. so, num is prime.
}
int main()
{
int testNumber;
cout<< "Enter testNumber: ";
cin>> testNumber;
for (int i = 0; i < testNumber; ++i)
{
int newLow, low, high, lowestPrime = 0, highestPrime = -1;
cin>> low>> high;
newLow = low;
if (low == high)
{
cout<<"0\n";
continue;
}
for (int j = low; j <= high; ++j)//find the lowest prime
{
isPrime(j, &lowestPrime);
if (lowestPrime != 0)//if lowest prime found, lowestprime will no longer be 0
{
//cout<<"lowest prime: "<<lowestPrime<<endl;
newLow = j; //there is no prime number between low...newLow
break;
}
}
for (int j = high; j >= newLow; j--)//find highest prime
{
isPrime(j, &highestPrime);
if (highestPrime != -1)//if highest prime found, highestprime will no longer be -1
{
//cout<<"highest prime: "<<highestPrime<<endl;
break;
}
}
cout<<highestPrime - lowestPrime<<"\n";
}
return 0;
}
This task doesn't require any special algorithm(except checking if number is prime in O(sqrt(N))) to be solved efficiently. Think about prime numbers, what is the frequency of them on some range (for example on range from 1 to 100) what is some "pattern" that appears. Now, if i understood the task correctly you need to find maximal difference of primes on range which is last_prime_on_range - first_prime_on_range, from this and previous observation you can easily devise an efficient algorithm.
Spoiler:
You don't need to check whole range, it would be enough to check from L to L+100
and from R to R-100, obviously if L+100>R you can just go from L to R.
If you want to be sure you can go from L to L+1000 and from R to R-1000 since it doesn't impact time complexity too much.
Also, adding a break; when you find a prime would also solve the problem.
Note that this gap between primes is not guaranteed to be bellow 100/1000 but for given range checking up to 1000 would be enough.
Now if you need to check all primes in range, you should learn about Sieve Of Eratosthenes.

Problem with Running test on CodeWare.com

is there any thing wrong with my code? this a question from codewar and I am trying to solve, and it worked on atom but when I ran a test on website, it showed an error?
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Finish the solution so that it returns the sum of all the multiples of 3 or 5 below the number passed in.
Note: If the number is a multiple of both 3 and 5, only count it once. Also, if a number is negative, return 0(for languages that do have them)
link of the question https://www.codewars.com/kata/514b92a657cdc65150000006/train/c
#include <stdio.h>
int sum_of_mul_of_3or5(int n)
{
if(n<0){return 0;}
int s = n,sum = 0,array[s];
for(int i=1; i<n;i++)
{
array[i-1] = 0;
if(i%3 == 0|| i%5 == 0){array[i-1] = i;}
sum += array[i-1];
}
for(int i=0; i<n; i++)
{
printf("%d ",array[i]);
}
return sum;
}
int main(){
int limit; printf("Enter a limit number: "); scanf("%d",&limit);
int sum = sum_of_mul_of_3or5(limit);
printf("\n");
printf("%d",sum);
return 0;}
Your algorithm is O(N) - it should be O(1).
Count how many 15 under given n. e.g 200, there are N=13 chunks of length 15. Every 15 (from K to K+14) you get K,K+3,K+5,K+6,K+9,K+10,K+12, total 7N+45. Sum them up, simply use N(N+1)/2*7+45N. Then add back the extra ending parts you have not accounted between 195 and 199.

I want to optimize this program

I have recently started to learn c and as a programming exercise, I've written a program that computes and lists out prime numbers from 0 up to a maximum entered by the user. It's a rather short program so I'll post the source code here.
// playground.c
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
int main ()
{
int max;
printf("Please enter the maximum number up to which you would like to see all primes listed: "
); scanf("%i", &max);
printf("All prime numbers in the range 0 to %i:\nPrime number: 2\n", max);
bool isComposite;
int primesSoFar[(max >> 1) + 1];
primesSoFar[0] = 2;
int nextIdx = 1;
for (int i = 2; i <= max; i++)
{
isComposite = false;
for (int k = 2; k <= (int)sqrt(i) + 1; k++)
{
if (k - 2 < nextIdx)
{
if (i % primesSoFar[k - 2] == 0)
{
isComposite = true;
k = primesSoFar[k - 2];
}
}else
{
if (i % k == 0) isComposite = true;
}
}
if (!isComposite)
{
printf("Prime number: %i\n", i);
primesSoFar[nextIdx] = i;
nextIdx++;
}
}
double primeRatio = (double)(nextIdx + 1) / (double)(max);
printf("The ratio of prime numbers to composites in range 0 to %d is %lf", max, primeRatio);
return 0;
}
I have become strangely fascinated with optimizing this program but I've hit a wall. The array primesSoFar is allocated based on a computed maximum size which ideally would be no larger than the number of prime numbers from 0 to max. Even if it were just slightly larger, that would be fine; as long as it's not smaller. Is there a way to compute the size the array needs to be that doesn't depend on first computing the primes up to max?
I've updated the code both applying suggested optimizations and adding internal documentation wherever it seemed helpful.
// can compute all the primes up to 0x3FE977 (4_188_535). Largest prime 4_188_533
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
int main ()
{
int max;
printf("Please enter the maximum number up to which you would like to see all primes listed: "
); scanf("%i", &max);
// The algorithm proper doesn't print 2.
printf("All prime numbers in the range 0 to %i:\nPrime number: 2\n", max);
bool isComposite;
// primesSoFar is a memory hog. It'd be nice to reduce its size in proportion to max. The frequency
// of primes diminishes at higher numerical ranges. A formula for calculating the number of primes for
// a given numerical range would be nice. Sadly, it's not linear.
int PRIMES_MAX_SIZE = (max >> 1) + 1;
int primesSoFar[PRIMES_MAX_SIZE];
primesSoFar[0] = 2;
int nextIdx = 1;
int startConsecCount = 0;
for (int i = 2; i <= max; i++)
{
isComposite = false; // Assume the current number isn't composite.
for (int k = 2; k <= (int)sqrt(i) + 1; k++)
{
if (k - 2 < nextIdx) // Check it against all primes found so far.
{
if (i % primesSoFar[k - 2] == 0)
{
// If i is divisible by a previous prime number, break.
isComposite = true;
break;
}else
{
// Prepare to start counting consecutive integers at the largest prime + 1. if i
// isn't divisible by any of the primes found so far.
startConsecCount = primesSoFar[k - 2] + 1;
}
}else
{
if (startConsecCount != 0) // Begin counting consecutively at the largest prime + 1.
{
k = startConsecCount;
startConsecCount = 0;
}
if (i % k == 0)
{
// If i is divisible by some value of k, break.
isComposite = true;
break;
}
}
}
if (!isComposite)
{
printf("Prime number: %i\n", i);
if (nextIdx < PRIMES_MAX_SIZE)
{
// If the memory allocated for the array is sufficient to store an additional prime, do so.
primesSoFar[nextIdx] = i;
nextIdx++;
}
}
}
// I'm using this to get data with which I can find a way to compute a smaller size for primesSoFar.
double primeRatio = (double)(nextIdx + 1) / (double)(max);
printf("The ratio of prime numbers to composites in range 0 to %d is %lf\n", max, primeRatio);
return 0;
}
edit: primesSoFar should be half the size of the range 0 to max. No doubt that's caused some confusion.
I can give you two main ideas as I have worked on a project discussing this problem.
A prime number bigger than 3 is either 6k-1 or 6k+1, so for example 183 can't be prime because 183=6x30+3, so you don't even have to check it. (Be careful, this condition is necessary but not sufficient, 25 for exemple is 6x4+1 but is not prime)
A number is prime if it can't be divided by any prime number smaller or equal to its root, so it's preferable to take a benefit out of the smaller primes you already found.
Thus, you can start with a primesList containing 2 and 3, and iterate k to test all the 6k-1 and 6k+1 numbers (5, 7, 11, 13, 17, 19, 23, 25...) using the second rule I gave you, by using division on elements in the primesList which are smaller than or equal to the root of the number you are checking, if you found only one element dividing it, you just stop and pass to another element, 'cause this one is not prime, otherwise (if no one can divide it): update the primesList by adding this new prime number.
There is some debugging to be done first.
When I saw that the test was <= my brain said BUG as Arrays are subscripted from 0 .. max - 1.
for (int i = 2; i <= max; i++)
So I went to look at the array.
int primesSoFar[(max >> 1) + 1];
Oh he is adding one to the size so it should be ok.
Wait. Why is that shift in there? (max >> 1) is a divide by two.
I compiled the code and ran it, and MSVC reported a memory error.
I removed the shift, and the memory error report went away. The program worked as expected.
With that out of the way, PiNaKa30 and II Saggio Vecchino have very good advice. The choice of algorithm is going to effect the performance dramatically.
Mat gives very good advice. Read the Wikipedia entry. It is filled with wonderful information.
Picking the correct algorithm is key.
How you represent the data you are checking is a factor. int has a maximum value it can hold.
A performance profiler can tell you lots of useful information about where the Hot Spots are in your program.
Congratulations on your efforts in learning C. You picked a very good learning path.
The source code that follows is basically a rewrite. It's running now as I write this. I entered 0x7FFF_FFFF, the 32-bit signed integer positive maximum. In mere minutes on my Acer aspire laptop running on an AMD ryzen 3 with Linux Mint it's already in the hundreds of millions! The memory usage of the old version was half of max, rendering anything larger than 0x3EF977 impossible on my 4gb of RAM. Now it only uses 370728 bytes of memory for its array data when computing primes from 0 to 2_147_483_647.
/*
A super optimized prime number generator using my own implementation of the sieve of Eratosthenes.
*/
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
int main ()
{
int max;
printf("Please enter the maximum to which you would like to see all primes listed: "
); scanf("%i", &max);
/*
Primes and their multiples will be stored until the next multiple of the prime is larger than max.
That prime and its corresponding multiple will then be replaced with a new prime and its corresponding
multiple.
*/
int PRIMES_MAX_SIZE = (int)sqrt(max) + 1;
int primes[PRIMES_MAX_SIZE];
int multiples[PRIMES_MAX_SIZE];
primes[0] = 2;
multiples[0] = 2;
int nextIdx = 1;
int const NO_DISPOSE_SENTINAL_VALUE = -1;
int nextDispose = NO_DISPOSE_SENTINAL_VALUE;
int startConsecCount = 0;
int updateFactor;
bool isComposite;
printf("All prime numbers in the range 0 to %i:\n\n", max);
// Iterate from i = 2 to i = max and test each i for primality.
for (int i = 2; i <= max; i++)
{
isComposite = false;
/*
Check whether the current i is prime by comparing it with the current multiples of
prime numbers, updating them when they are less than the current i and then proceeding
to check whether any consecutive integers up to sqrt(i) divide the current i evenly.
*/
for (int k = 2; k < (int)sqrt(i) + 1; k++)
{
if (k < nextIdx)
{
// Update the multiple of a prime if it's smaller than the current i.
if (multiples[k] < i)
{
updateFactor = (int)(i / primes[k]);
multiples[k] = updateFactor * primes[k] + primes[k];
// Mark the value for disposal if it's greater than sqrt(max).
if (multiples[k] > (int)sqrt(max)) nextDispose = k;
}
if (i == multiples[k])
{
isComposite = true;
break;
}else
{
startConsecCount = multiples[k] + 1;
}
} else
{
if (startConsecCount != 0)
{
k = startConsecCount;
startConsecCount = 0;
}
if (i % k == 0)
{
isComposite = true;
break;
}
}
}
/*
Print the prime numbers and either insert them at indices occupied by disposed primes or at
the next array index if available.
*/
if (!isComposite)
{
printf("Prime number: %i\n", i);
if (nextDispose != NO_DISPOSE_SENTINAL_VALUE)
{
primes[nextDispose] = i;
// This will trigger the update code before the comparison in the inner loop.
multiples[nextDispose] = 0;
nextDispose = NO_DISPOSE_SENTINAL_VALUE;
}else
{
if (nextIdx < PRIMES_MAX_SIZE)
{
primes[nextIdx] = i;
multiples[nextIdx] = 0;
}
}
}
}
return 0;
}
This thing will do the old 0 to 0x3EF977 in the blink of an eye. The old version couldn't do the 32-bit maximum on my system. It's on 201 million + already. I am super chuffed with the results. Thank you for your advice. I wouldn't have made it this far without help.

How can I find sum mean of 2d array with positive number and negative number in c [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
How can I find sum mean of 2d array with positive number and negative number in c
int data[4][5] = {
{3,-6,1,-5,7},
{-2,9,-3,5,4},
{7,3,-4,0,-6},
{9,-2,-5,8,3}
};
>Sum of all positive number
>Mean of all positve number
>Sum of all negative number
>Mean of all negative number
I'm freshman from university and I have final exam tomorrow please help me practice. Thanks!
Here is some code that works on a 1D array. You can understand this, and apply it to your 2D problem.
We need variables to keep track of two sums (positive and negative numbers), these can be ints. We need two variables to count how many positive and negative numbers are in the array, and these can also be ints. Then we need two variables to store the means in. These could be floats, but it is better to just use doubles for this type of calculation. Finally, we need a variable to index the array with. I usually use a size_t variable for this sort of thing, but here I will use another int.
After looping through the array to find sums and counts, it is time to calculate the means. One pitfall to watch out for here is that all of the arguments are of type int, so if we calculated:
mean_pos = sum_pos / count_pos;
we would be using integer division, and losing the fractional part of the result. We can multiply count_pos * 1.0 to convert this value to a double and use floating point division.
I should point out that this code does not count zero values, which is what your problem specification suggested. If you want to count the zeros (which are neither positive or negative) in one of the means, it should be a simple matter for you to modify the code.
Good luck with your tests.
#include <stdio.h>
int main(void)
{
int data[10] = { 3, -6, 1, -5, 7, -2, 9, -3, 5, 4 };
int sum_pos = 0;
int sum_neg = 0;
int count_pos = 0;
int count_neg = 0;
double mean_pos, mean_neg;
int i;
for (i = 0; i < 10; i++) {
if (data[i] > 0) {
sum_pos += data[i];
++count_pos;
} else if (data[i] < 0) {
sum_neg += data[i];
++count_neg;
}
}
mean_pos = sum_pos / (count_pos * 1.0);
mean_neg = sum_neg / (count_neg * 1.0);
printf("Sum of positive numbers: %d\n", sum_pos);
printf("Mean of positive numbers: %f\n", mean_pos);
printf("Sum of negative numbers: %d\n", sum_neg);
printf("Mean of negative numbers: %f\n", mean_neg);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define ROWS 4
#define COLS 5
int
main(void) {
int data[ROWS][COLS] = {{3,-6,1,-5,7},
{-2,9,-3,5,4},
{7,3,-4,0,-6},
{9,-2,-5,8,3}};
int numpos = 0, numneg = 0;
int possum = 0, negsum = 0;
int row, col;
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
if (data[row][col] > 0) {
possum += data[row][col];
numpos++;
} else if (data[row][col] < 0) {
negsum += data[row][col];
numneg++;
}
}
}
printf("Sum of all positive numbers = %d\n", possum);
printf("Mean of all positive numbers = %.2f\n", ((1.0) * possum) / numpos);
printf("Sum of all negative numbers = %d\n", negsum);
printf("Mean of all negative numbers = %.2f\n", ((1.0) * negsum) / numneg);
return 0;
}

How to find the largest prime factor of 600851475143 in C? [duplicate]

This question already has answers here:
How to find the largest prime factor of 600851475143?
(5 answers)
Closed 7 years ago.
I try to find the largest prime factor of 600851475143 with the code as given below.
However, this code does not return any output, not even errors or warnings.
Where do I go wrong?
Code:
#include <stdio.h>
int main()
{
int i, j, k, mpf;
for (i = 1; i < 600851475143; i++)
{
if (600851475143 % i == 0)
{
k = 0;
for (j = 1; j <= i; j++)
if (i % j == 0)
k++;
if (k == 2)
mpf = i;
}
}
printf("\nThe largest prime factor of 600851475143 is: %ld\n", mpf);
return 0;
}
Looping up to 600 billion will take forever — not just a long time, but impossible because it exceeds what can be stored in an int (usually up to 2^31-1 these days, but could be as small as 2^15-1 according to the C standard).
What you need is a smarter algorithm. Rather than giving you the solution verbatim, I suggest that you look at existing answers and work out a solution in C by yourself.
Instead of looping from 1 to 600851475143, you should loop from 2 to the square root of 600851475143:
long long num=600851475143;
long i=2;
while(i<=sqrt(num))
{
//printf("%lu\n",num);
if(num%i==0)
{
while(num%i==0)
{
num/=i;
}
if(num==1)
{
num=i;
break;
}
}
else
{
i++;
}
}
printf("%lu",num);

Resources