I'm trying to answer this question:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
Here is my code:
#include <stdio.h>
int isPrime(long long num)
{
for (long long k = 1; k < num; k++)
{
if (num%k == 0)
return 0;
}
return 1;
}
long long num = 600851475143;
int main(void)
{
long long prime_factor = 0;
for (long long j = 2; j < num; j++)
{
if (num % j == 0 && isPrime(j) == 1)
prime_factor = j;
}
printf("%lli\n", prime_factor);
}
But for some reason it doesn't print anything, or even end. What is causing this?
That's a terribly inefficient way of finding the prime factors of a number.
To find the prime factors, you should:
Create a static list of primes less than or equal to (number / 2).
Iterate over each element in the list of primes and see if each
one can evenly divide the number.
Divide the original number by the prime, and check the last number
again.
Why? Well the smallest prime is 2. If the number isn't even then the first prime that can divide any number > 2 is 3.
Every number can be uniquely identified by its prime factors. This is called the Fundamental Theorem of Arithmetic. That means that there is only one way to represent e.g. 15 as a product of primes, in this case { 3, 5 }.
However any prime can divide a number more than once. For example, 49 is the product of two primes { 7, 7 }. Dividing the original number by one of its factors makes subsequent divisions quicker. And you can logically stop checking when the number == 1.
It doesn't print anything because it never leaves the loop, after which is found the only line which prints anything in the code. Try a smaller number and see if it ends.
Related
Is there any simple way to make this small program faster? I've made it for an assignment, and it's correct but too slow. The aim of the program is to print the nth pair of primes where the difference between the two is two, given n.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
bool isPrime(int number) {
for (int i = 3; i <= number/2; i += 2) {
if (!(number%i)) {
return 0;
}
}
return 1;
}
int findNumber(int n) {
int prevPrime, currentNumber = 3;
for (int i = 0; i < n; i++) {
do {
prevPrime = currentNumber;
do {
currentNumber+=2;
} while (!isPrime(currentNumber));
} while (!(currentNumber - 2 == prevPrime));
}
return currentNumber;
}
int main(int argc, char *argv[]) {
int numberin, numberout;
scanf ("%d", &numberin);
numberout = findNumber(numberin);
printf("%d %d\n", numberout - 2, numberout);
return 0;
}
I considered using some kind of array or list that would contain all primes found up until the current number and divide each number by this list instead of all numbers, but we haven't really covered these different data structures yet so I feel I should be able to solve this problem without. I'm just starting with C, but I have some experience in Python and Java.
To find pairs of primes which differ by 2, you only need to find one prime and then add 2 and test if it is also prime.
if (isPrime(x) && isPrime(x+2)) { /* found pair */ }
To find primes the best algorithm is the Sieve of Eratosthenes. You need to build a lookup table up to (N) where N is the maximum number that you can get. You can use the Sieve to get in O(1) if a number is prime. While building the Sieve you can build a list of sorted primes.
If your N is big you can also profit from the fact that a number P is prime iif it doesn't have any prime factors <= SQRT(P) (because if it has a factor > SQRT(N) then it should also have one < SQRT(N)). You can build a Sieve of Eratosthenes with size SQRT(N) to get a list of primes and then test if any of those prime divides P. If none divides P, P is prime.
With this approach you can test numbers up to 1 billion or so relatively fast and with little memory.
Here is an improvement to speed up the loop in isPrime:
bool isPrime(int number) {
for (int i = 3; i * i <= number; i += 2) { // Changed the loop condition
if (!(number%i)) {
return 0;
}
}
return 1;
}
You are calling isPrime more often than necessary. You wrote
currentNummber = 3;
/* ... */
do {
currentNumber+=2;
} while (!isPrime(currentNumber));
...which means that isPrime is called for every odd number. However, when you identified that e.g. 5 is prime, you can already tell that 10, 15, 20 etc. are not going to be prime, so you don't need to test them.
This approach of 'crossing-out' multiples of primes is done when using a sieve filter, see e.g. Sieve of Eratosthenes algorithm in C for an implementation of a sieve filter for primes in C.
Avoid testing ever 3rd candidate
Pairs of primes a, a+2 may only be found a = 6*n + 5. (except pair 3,5).
Why?
a + 0 = 6*n + 5 Maybe a prime
a + 2 = 6*n + 7 Maybe a prime
a + 4 = 6*n + 9 Not a prime when more than 3 as 6*n + 9 is a multiple of 3
So rather than test ever other integer with + 2, test with
a = 5;
loop {
if (isPrime(a) && isPrime(a+2)) PairCount++;
a += 6;
}
Improve loop exit test
Many processors/compilers, when calculating the remainder, will also have available, for nearly "free" CPU time cost, the quotient. YMMV. Use the quotient rather than i <= number/2 or i*i <= number to limit the test loop.
Use of sqrt() has a number of problems: range of double vs. int, exactness, conversion to/from integer. Recommend avoid sqrt() for this task.
Use unsigned for additional range.
bool isPrime(unsigned x) {
// With OP's selective use, the following line is not needed.
// Yet needed for a general purpose `isPrime()`
if (x%2 == 0) return x == 2;
if (x <= 3) return x == 3;
unsigned p = 1;
unsigned quotient, remainder;
do {
p += 2;
remainder = x%p;
if (remainder == 0) return false;
quotient = x/p; // quotient for "free"
} while (p < quotient); // Low cost compare
return true;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
int anz;
scanf("%d", &anz);
time_t start = time(0);
int *primZ = malloc(anz * sizeof(int));
primZ[0] = 2;
int Num = 0;
for (int i = 1, num = 3; i < anz; num += 2) {
for (int j = 1; j < i; j++) {
if (num % primZ[j] == 0) {
num += 2;
j = 0;
}
//this part
if (primZ[j] > i / 2)
break;
}
primZ[i] = num;
i++;
printf("%d ,",num);
}
time_t delta = time(0) - start;
printf("%d", delta);
getchar();
getchar();
return 0;
}
The code works perfectly fine, the question is why. The part if(primZ[j] > i/2) makes the program 2 - 3 times faster. It was actually meant to be if(primZ[j] > num/3) which makes perfect sense because num can only be an odd number. But it is the number of found prime numbers. It makes no sense to me. Please explain.
You check if the prime is composite by checking if it divisible by already found prime numbers. But in doing so you only have to check up to and including the square root of the number because any number larger than that that divides the number will leave a smaller number than the square root of the number.
For example 33 is composite, but you only have to check numbers up to 5 to realize that, you don't need to check it being divisible by 11 because it leaves 3 (33/11=3) which we already checked.
This means that you could improve your algorithm by
for (int j = 1; j < i; j++) {
if( primZ[j]*primZ[j] > num )
break;
if (num % primZ[j] == 0) {
num += 2;
j = 0;
}
}
The reason you can get away with comparing with cutting of at i/2 is due to the distribution of the prime numbers. The prime counting function is approximately i = num/log(num) and then you get that i/2 > sqrt(num).
The reason is that the actual bound is much tighter than num/3 - you could use:
if (primZ[j] > sqrt(num))
The reason for that being that if a prime higher than the square root of num divides num, there must also be a lower prime that does (since the result of such a division must be lower than the square root).
This means that as long as i/2 is higher than sqrt(num), the code will work. What happens is that the number of primes lower than a number grows faster than the square root of that number, meaning that (completely accidentally) i/2 is a safe bound to use.
You can check out how your i value behaves here - they call it pi(x), the number of primes less than x.
It makes sense, since if n has two factors one of them is surely less than or equal to n/2, sense the program found no factors of i in primZ that are less than or equal to i/2 it means there's no factors of i -except 1 of course-.
Sense primZ is sorted in ascending order and j only increases, when primeZ[j] > i/2 it indicates that there's no factors of i in primZ that are less than i/2.
P.S.The point of starting the search is stated in the first part of the for statement num=3 , and the recurring statement num += 2 ensures you only test odd numbers
I wrote this program per my professor's instruction. Turns out he wanted us to use a SINGLE do-while loop. While I did technically do that... this won't fly. I can't figure out how to do it without using a for-loop or at least another loop of some other type. He said it could use continue or break statements--but that it might not be necessary.
I would appreciate not just re-writing my code--while this is handy, I don't learn from it well.
I appreciate any and all help.
int main() {
int max, x, n = 2; //init variables
//start n at 2 because 1 isn't prime ever
//asks user for max value
printf("Enter max number: ");
scanf("%i", &max);
/*prints prime numbers while the max value
is greater than the number being checked*/
do {
x = 0; //using x as a flag
for (int i = 2; i <= (n / 2); i++) {
if ((n % i) == 0) {
x = 1;
break;
}
}
if (x == 0) //if n is prime, print it!
printf("%i\n", n);
n++; //increase number to check for prime-ness
} while (n < max);
return 0;
}
This is definitely doable. The trick is to have a test variable, and each iteration through your while loop, check the test variable against your current number. Always start the test variable at 2 (every natural number > 0 is divisible by 1)
Cases to consider:
Our current number is divisible by the test variable -- number is NOT prime, increase the current number and reset the test variable.
Our test variable is greater than the square root of the current number. By definition, it CANNOT divide the current number, so the current number has to be prime (we have tried all numbers lower than the square root of the current number and none of them divide it). Increase the current number and reset the test variable.
Lastly, if either above case isn't true, we have to try the next number higher. Increment the test variable.
I have not provided the code as you asked to not have it re-written, but can provide if you would like.
EDIT
#include <stdio.h>
#include <math.h>
int main(void)
{
int max = 20;
int current = 4;
int checker = 2;
do{
if(checker > sqrt((double)current))
{
checker = 2;
printf("%d is prime\n",current);
current++;
}
else if(current % checker == 0)
{
checker = 2;
printf("%d is NOT prime\n",current);
current++;
}
else
checker++;
}while(current < max);
}
Output:
4 is NOT prime
5 is prime
6 is NOT prime
7 is prime
8 is NOT prime
9 is NOT prime
10 is NOT prime
11 is prime
12 is NOT prime
13 is prime
14 is NOT prime
15 is NOT prime
16 is NOT prime
17 is prime
18 is NOT prime
19 is prime
I won't give you the exact code, but two pointers that should help you:
First, a for loop can be written as a while loop (and, vice versa)
for (int i=0; i< 100; ++i)
...
would become:
int i=0;
while (i < 100)
{
...
++i;
}
Second, two nested loops can become a single one, in any number of ways:
for (int i=0; i< 100; ++i)
for (int j=0; j< 100; ++j)
...
Becomes
for (int z=0; z< 100*100; ++z)
{
i = z / 100;
j = z % 100;
}
The above shows two for loops, but you can perform similar transforms on other loops.
Think Eratosthenes sieve. In this method we strike composite numbers out of a table, so that in the end only primes remain. For simplicity, the table contains only odd numbers. You start pointing at 3, which is a prime. Strike out 3*3, 3*5... Finish your run over the table (it's finite), point at 5. It's not striked out, thus a prime. Strike out 15, 25... check 7, prime, strike 21, 35... check 9, already striked out, move on to 11...
Questions:
You have just checked a number, what is the next number to check?
How do you know you've ran out of numbers to check?
Write down answers to these questions, and you have a one-loop prime-finding algorithm.
I've been trying to solve the SPOJ problem of Prime number Generator Algorithm.
Here is the question
Peter wants to generate some prime numbers for his cryptosystem. Help
him! Your task is to generate all prime numbers between two given
numbers!
Input
The input begins with the number t of test cases in a single line
(t<=10). In each of the next t lines there are two numbers m and n (1
<= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output
For every test case print all prime numbers p such that m <= p <= n,
one number per line, test cases separated by an empty line.
It is very easy, but the online judge is showing error, I didn't get what the problem meant by 'test cases' and why that 1000000 range is necessary to use.
Here is my code.
#include<stdio.h>
main()
{
int i, num1, num2, j;
int div = 0;
scanf("%d %d", &num1, &num2);
for(i=num1; i<=num2; i++)
{
for(j=1; j<=i; j++)
{
if(i%j == 0)
{
div++;
}
}
if(div == 2)
{
printf("%d\n", i);
}
div = 0;
}
return 0;
}
I can't comment on the alogirthm and whether the 100000 number range allows optimisations but the reason that your code is invalid is because it doesn't seem to be parsing the input properly. The input will be something like:
2
123123123 123173123
987654321 987653321
That is the first line will give the number of sets of input you will get with each line then being a set of inputs. Your program, at a glance, looks like it is just reading the first line looking for two numbers.
I assume the online judge is just looking for the correct output (and possibly reasonable running time?) so if you correct for the right input it should work no matter what inefficiencies are in your algorithm (as others have started commenting on).
The input begins with the number t of test cases in a single line (t<=10)
you haven't got test cases in your programm.
Its wrong
And sorry for my English
2 - //the number of test cases
1 10 - // numbers n,m
3 5 - // numbers
Your programm will work only in first line.
#include <stdio.h>
#include <math.h>
int main()
{
int test;
scanf("%d",&test);
while(test--)
{
unsigned int low,high,i=0,j=2,k,x=0,y=0,z;
unsigned long int a[200000],b[200000];
scanf("%d",&low);
scanf("%d",&high);
for(i=low;i<=high;i++)
a[x++]=i;
for(i=2;i<=32000;i++)
b[y++]=i;
i=0;
while(b[i]*b[i]<=high)
{
if(b[i]!=0)
{
k=i;
for(;k<y;k+=j)
{
if(k!=i)
{
b[k]=0;
}
}
}
i+=1;j+=1;
}
for(i=0;i<y;i++)
{
if(b[i]!=0 && (b[i]>=low && b[i]<=sqrt(high)))
printf("%d\n",b[i]);
}
int c=0;
for(i=0;i<y;i++)
{
if(b[i]!=0 && (b[i]>=1 && b[i]<=sqrt(high)))
b[c++]=b[i];
}
int m=a[0];
for(i=0;i<c;i++)
{
z=(m/b[i])*b[i];k=z-m;
if(k!=0)
k += b[i];
for(;k<x;)
{
if(a[k]!=0)
{
a[k]=0;
}
k+=b[i];
}
}
for(i=0;i<x;i++)
{
if(a[i]!=0 && (a[i]>=2 && a[i]<=(high)))
printf("%d\n",a[i]);
}
printf("\n");
}
return 0;
}
To find primes between m,n where 1 <= m <= n <= 1000000000, n-m<=100000, you need first to prepare the core primes from 2 to sqrt(1000000000) < 32000. Simple contiguous sieve of Eratosthenes is more than adequate for this. (Having sieved the core bool sieve[] array (a related C code is here), do make a separate array int core_primes[] containing the core primes, condensed from the sieve array, in an easy to use form, since you have more than one offset segment to sieve by them.)
Then, for each given separate segment, just sieve it using the prepared core primes. 100,000 is short enough, and without evens it's only 50,000 odds. You can use one pre-allocated array and adjust the addressing scheme for each new pair m,n. The i-th entry in the array will represent the number o + 2i where o is an odd start of a given segment.
See also:
Is a Recursive-Iterative Method Better than a Purely Iterative Method to find out if a number is prime?
Find n primes after a given prime number, without using any function that checks for primality
offset sieve of Eratoshenes
A word about terminology: this is not a "segmented sieve". That refers to the sieving of successive segments, one after another, updating the core primes list as we go. Here the top limit is known in advance and its square root is very small.
The same core primes are used to sieve each separate offset segment, so this may be better described as an "offset" sieve of Eratosthenes. For each segment being sieved, only the core primes not greater than its top limit's square root need be used of course; but the core primes are not updated while each such offset segment is sieved (updating the core primes is the signature feature of the "segmented" sieve).
For such small numbers you can simply search for all primes between 1 and 1000000000.
Take 62.5 mByte of RAM to create a binary array (one bit for each odd number, because we already know that no even number (except of 2) is a prime).
Set all bits to 0 to indicate that they are primes, than use a Sieve of Eratosthenes to set bits to 1 of all number that are not primes.
Do the sieve once, store the resulting list of numbers.
int num;
bool singleArray[100000];
static unsigned long allArray[1000000];
unsigned long nums[10][2];
unsigned long s;
long n1, n2;
int count = 0;
long intermediate;
scanf("%d", &num);
for(int i = 0; i < num; ++i)
{
scanf("%lu", &n1);
scanf("%lu", &n2);
nums[i][0] = n1;
nums[i][1] = n2;
}
for(int i = 0; i < 100000; ++i)
{
singleArray[i] = true;
}
for(int i = 0; i < num; ++i)
{
s = sqrt(nums[i][1]);
for(unsigned long k = 2; k <= s; ++k)
{
for (unsigned long j = nums[i][0]; j <= nums[i][1]; ++j)
{
intermediate = j - nums[i][0];
if(!singleArray[intermediate])
{
continue;
}
if((j % k == 0 && k != j) || (j == 1))
{
singleArray[intermediate] = false;
}
}
}
for(unsigned long m = nums[i][0]; m <= nums[i][1]; ++m)
{
intermediate = m - nums[i][0];
if(singleArray[intermediate])
{
allArray[count++] = m;
}
}
for(int p = 0; p < (nums[i][1] - nums[i][0]); ++p)
{
singleArray[p] = true;
}
}
for(int n = 0; n < count; ++n)
{
printf("%lu\n", allArray[n]);
}
}
Your upper bound is 10^9. The Sieve of Eratosthenes is O(N loglogN) which is too much for that bound.
Here are a few ideas:
Faster primality tests
The problem with a naive solution where you loop over the range [i, j] and check whether each number is prime is that it takes O(sqrt(N)) to test whether a number is prime which is too much if you deal with several cases.
However, you could try a smarter primality testing algorithm. Miller-Rabin is polynomial in the number of bits of N, and for N <= 10^9, you only need to check a = 2, 7 and 61.
Note that I haven't actually tried this, so I can't guarantee it would work.
Segmented sieve
As #KaustavRay mentioned, you could use a segmented sieve. The underlying idea is that if a number N is composite, then it has a prime divisor that is at most sqrt(N).
We use the Sieve of Eratosthenes algorithm to find the prime numbers below 32,000 (roughly sqrt(10^9)), and then for each number in the range [i, j] check whether there is any prime below 32,000 that divides it.
By the prime number theorem about one in log(N) numbers are prime which is small enough to squeeze in the time limit.
#include <iostream>
using namespace std;
int main() {
// your code here
unsigned long int m,n,i,j;int N;
cin>>N;
for(;N>0;N--)
{
cin>>m>>n;
if(m<3)
switch (n)
{
case 1: cout<<endl;continue;
case 2: cout<<2<<endl;
continue;
default:cout<<2<<endl;m=3;
}
if(m%2==0) m++;
for(i=m;i<=n;i+=2)
{
for(j=3;j<=i/j;j+=2)
if(i%j==0)
{j=0;break;}
if(j)
cout<<i<<endl;
}
cout<<endl;
}return 0;}
This is a program to count the number of divisors for a number, but it is giving one less divisor than there actually is for that number.
#include <stdio.h>
int i = 20;
int divisor;
int total;
int main()
{
for (divisor = 1; divisor <= i; divisor++)
{
if ((i % divisor == 0) && (i != divisor))
{
total = total++;
}
}
printf("%d %d\n", i, total);
return 0;
}
The number 20 has 6 divisors, but the program says that there are 5 divisors.
&& (i != divisor)
means that 20 won't be considered a divisor. If you want it to be considered, ditch that bit of code, and you'll get the whole set, {1, 2, 4, 5, 10, 20}.
Even if you didn't want the number counted as a divisor, you could still ditch that code and just use < instead of <= in the for statement.
And:
total = total++;
is totally unnecessary. It may even be undefined, I'm just too lazy to check at the moment and it's not important since nobody writes code like that for long :-)
Use either:
total = total + 1;
or (better):
total++;
Divisor counting is perhaps simpler and certainly faster than any of these. The key fact to note is that if p is a divisor of n, then so is n/p. Whenever p is not the square root of n, then you get TWO divisors per division test, not one.
int divcount(int n)
{
int i, j, count=0;
for (i=1, j=n; i<j; j = n/++i)
{
if (i*j == n)
count += 2;
}
if (i == j && i*j == n)
++count;
return count;
}
That gets the job done with sqrt(n) divisions, and sqrt(n) multiplications. I choose that because, while j=n/i and another j%i can be done with a single division instruction on most CPUs, I haven't seen compilers pick up on that optimization. Since multiplication is single-clock on modern desktop processors, the i*j == n test is much cheaper than a second division.
PS: If you need a list of divisors, they come up in the loop as i and j values, and perhaps as the i==j==sqrt(n) value at the end, if n is a square.
You have added an extra check && (i != divisor) as explained in given answer.
Here, I wrote the same program using the prime factorisation. This is quick way to find the number of divisor for large number (reference).
// this function return the number of divisor for n.
// if n = (m^a) (n^b) ... where m, n.. are prime factors of n
// then number of divisor d(n) = (a+1)*(b+1)..
int divisorcount(int n){
int divider = 2;
int limit = n/2;
int divisorCount = 1;
int power = 0;
// loop through i=2...n/2
while(divider<=limit){
if(n%divider==0){
// dividing numper using prime factor
// (as smallest number devide a number
// is it's prime factor) and increase the
// power term for prime factor.
power++;
n/=divider;
}
else{
if(power != 0){
// use the prime factor count to calculate
// divisor count.
divisorCount*=(power+1);
}
power = 0;
divider++;
// if n become 1 then we have completed the
// prime factorization of n.
if(n==1){
break;
}
}
}
return divisorCount;
}