Find Prime Number 10001 Optimization Questions - c

So I have created a program that finds the 10,001st prime number. Here is the main for that program:
int main(){
int i;
int j;
int count=0;
int currnumber=0;
for(i=1; count < 10002; i++){
if(isPrime(i)){
count++;
currnumber = i;
if(count == 10002)
printf("%i",currnumber);
}
}
}
And here is the code for the IsPrime function I built in a custom library:
long long isPrime(long long number){
long long i = 2;
if(number == 2)
return 1;
for(i=2;i<number;i++){
if(number % i == 0)
return 0;
}
if(i >= number && ((number % 1 == 0) && (number % number == 0)))
return 1;
}
When I run the program, it works and gives me the correct answer(It's an Euler problem so I know i did it right :D), but it takes at least 6 seconds to process. So my questions are:
Why is it taking that long? Is it something to do with how i've set my algorithm?
How can I potentially improve my code to make it run faster?
Thanks in advance!

Probably the first thing you can do is cache the prime number values you do create, and use the sieve of eratosthenes algorithm in order to not have to constantly recalculate prime number values once you've found them.

You are using two for loops
A faster way which comes to my mind and is also a great exercise is the algorithm called: Sieve of Eratosthenes

There's a lot of optimisations that can be done. A few people have mentioned the sieve of Eratosthenes, which is right, but let me give you some additional pointers.
Improving your code without changing algorithm: As Michael Parker mentioned, you do not need to deal with the even numbers because only one of them is prime (the number 2, which makes it the 'oddest' prime of all -- that's a pun). You can do a similar trick by avoiding multiples of three, which boils down to only dealing with integers i which are either 1 or 5 more than a multiple of 6. To turn that into code, first set count to 3 to account for primes 2, 3, and 5. Then start i at 6 and test both i+1 and i+5 (both within the for loop), and then increment i by 6 every time.
For isPrime() you could add similar improvements but you can also stop trial dividing once you reach the square root of the number. This is because a number has a divisor >= sqrt(number) if and only if it has a divisor <= sqrt(number). To prove this, the key is that if a divides number, then number/a is another divisor (you can fill in remaining details because you are smart).
Improving your code by using Sieve of Eratosthenes: As many have mentioned, the sieve of Eratosthenes is much better for solving this. In fact, it is super-duper fast. But the one issue often overlooked is how big to make your sieve length to be sure that you captured the prime you are after, without making it outrageously large? The Prime Number Theorem gives an estimate to how big it should be. But you will need an upper bound. Suggest using n * (ln n * ln ln n).

If I understand correctly, you are taking every number less than 1001 and checking if it has a common denominator. This is extremely slow. The complexity is actually increasing exponentially. What you should do is combine this method with a sieve. Take any primes you find with the common denominator method and and multiply them from from 1 to n until you have all their multiple between 1 and 10001. That way you will skip testing the common denominator method on multiples of all the prime numbers you have already found. For example, try this:
ArrayList<Integer> List = new ArrayList<Integer>();
ArrayList<Integer> Primes = new ArrayList<Integer>();
Primes.add(2);
Integer p=2;
Integer n=105000;
Integer i=1;
while(p < n) {
i=1;
while((p*i)<=n){
List.add(p*i);
i++;
}
while (p < n){
p++;
if(List.contains(p)){}
else {Primes.add(p); break;}
}
}
System.out.println(Primes.get(10000));

Related

Segmented Sieve of eratosthenes algorithm

I am trying to solve "PRIME1"(http://www.spoj.com/problems/PRIME1/) on spoj.
A lot of people are saying that I should solve it using Segmented Sieve of eratosthenes. I understood Sieve of eratosthenes but How I can implement Segmented one? I've seen all most all the resources and couldn't understand properly.
This is the code I've written for Sieve of eratosthenes :
#include<stdio.h>
#include<math.h>
int main()
{
long long int i,n,j,m;
_Bool a[10000];
scanf(" %lld",&n);
for(i=2;i<=n;i++)
{
a[i]=1;
}
for(i=2;i<=sqrt(n);i++)
{
for(j=2;i*j<=n;j++)
{
a[i*j]=0;
}
}
for(i=1;i<=n;i++)
{
if(a[i]==1)
printf("%lld\n",i);
}
return 0;
}
From this, How can I implemet Segmented Sieve of eratosthenes. Please explain it in a beginner's perspective.
The idea is very simple:
Start from k=2
Compute where you would fall in after entering the interval; this is simply x=((m + k - 1)/k)*k. For example for m=12345 and k=7 you get 12348 and that's the smallest multiple of 7 greater than or equal to m.
Mark the spot associated to x as "taken" and keep adding k to x until you get past n
Increment k and repeat until you get past sqrt(n)
You don't need to test all values for k but only prime numbers. For that you can use a normal sieve to compute all primes not bigger than sqrt(n) (note that sqrt(1000000000) < 31623 is not a really big number and there are only 3401 primes in that range).
Pay attention to not "marking" x at the start of the inner loop if it happens to be equal to k; the minimum value to consider for x is 2*k.
You can stop at sqrt(n) instead of n because if you have a composite number t<n with t=p*q with p>1 and q>1 then it must be either p<sqrt(n) or q<sqrt(n) and therefore the spot for t has already been marked when you stop at k=sqrt(n).

Can I make this C program any faster?

I need to make a program which prints all the prime numbers, here is that I have done:
#include <stdio.h>
int main(void) {
long long t,m,n,i,i2,i3,found;
float p;
scanf ("%lld" , &t);
for (i=1;i<=t;i++) {
scanf ("%lld%lld" , &m ,&n);
for (i2=m;i2<=n;i2++) {
found=0;
for (i3=2;i3<=i2/2;i3++) {
p=(float)i2/i3;
p=p-i2/i3;
if (p==0) {
found=1;
}
}
if ((found==0) && (i2!=1)) {
printf ("%lld\n" , i2);
}
}
printf ("\n");
}
return 0;
}
my time limit is 6 seconds, and with this code it's impossible, also the difference between m and n is 100000 maximum, and 1<=n<=m<=1000000000
There are complicated mathematical algorithms, like the Sieve of Atkin, that can find primes very quickly, but for your purposes, consider:
Every non-prime number is factorable by primes, if factored far enough.
If you've reached the sqrt(n) and still haven't found it to be factorable, then it won't be factorable, because any number larger than sqrt(n) must be factored alongside a number smaller than sqrt(n) to achieve the number you're looking for.
So test every prime number from 2 to sqrt(n) to see if your n is a prime. If none of the primes between 2 and sqrt(n) are factors of n, then n must be prime.
This should meet with the speed requirements of your assignment.
For this problem the constraints (ranges) are very large so better to use Miller–Rabin primality test method.
I changed my mind. You can use Sieve of Eratosthenes algorithm.
Here are the steps to find all prime numbers less than or equal to a given integer n by Sieve of Eratosthenes method:
First create an array of consecutive integers from 2 to n: (2, 3, 4, ..., n).
let p be an integer variable, initialize it with 2, the first prime number.
Starting from p, count up in increments of p and cross out all the multiples of p less than or equal to n (2p, 3p, 4p .... kp <= n).
Take the first number greater than p in the array that is uncrossed. If there is no such number <= n,then stop. Otherwise, assign this new number in p (which is the next prime), and start from step 3.

How to find out how many times the prime number occurs?

I need to write a program to input a number and output it's factorial in the form in C
4!=(2^3)*(3^1)
5!=(2^3)*(3^1)*(5^1)
I am able to find the prime numbers 2, 3 and 5 but how do i figure out how many times they occur? (^3, ^1, ^1)
Code:
int main() {
int num,i,count,n;
printf("Enter to find prime numbers: ");
scanf("%d",&n);
for(num = 2; num<=n;num++) {
count = 0;
for(i=2;i<=num/2;i++) {
if(num%i==0)
{
count++;
break;
}
}
if(count==0 && num!= 1)
printf("%d ",num);
}
return 0;
}
Without going into any code, Ill explain what the problem in the way you are doing things ...
Let us say you want to find the prime factors of the factorial of 5. So you do:
5! = 2 x 3 x 4 x 5 (this is your outer loop (for(num = ...)
Let us say that for a particular iteration, num = 4. Then, you have another iteration in i that checks of each number upto that num/2 is a factor. Now for a small value of 5! this is not a problem. Consider a bigger number like 25!. In this case, your outer loop will be:
25! = 1 x 2 x 3 x ... 22 x 23 x 24 x 25
Now your outer iteration num goes much further. Consider now the number 24. 24/2 = 12. Your program is going to print all factors that divide 24 upto 12, which happen to be 2, 3, 4, 6, and 12. I am sure, that is not what you want.
First, do not attempt to find the factorial for large numbers. You will run into overflow issues. Next, Ill give you some pointers and hope you can solve the problem on your own. Its a very cool problem, so I really hope you are able to solve it:
Study the prime sieve algorithm (http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes). You will not be using this directly, but only the ideas mentioned here.
Create two arrays. The first one will contain the prime factors, while the next one will contain the total count of the factors occuring in the factorial.
For a particular num u need to be iterating not using the i that you have used but using the values in your prime array.
3.1. Use the method explained by Barmar to find the number of times this num is divisible by the factors, and update the corresponding counts in the count array.
Print out the factors and counts that you have obtained.
Finally, I think its a pretty good question. It teaches you how to not run into overflow errors and still be able to solve problem using the computer. It can teach you dynamic memory allocation and memory management skills, if that is the way you want to go. It also helps you to think critically about a problem. You dont deserve a -1. I have increased your rating.
Have fun programming, and keep thinking critically about each setp in your program.
Cheers!
for(num = 2; num<=n; ++num){
count = 0;
while(n % num == 0){
n /= num;
++count;
}
if(count!=0)
printf("(%d^%d)", num, count);
}

Algorithm - Find pure numbers

Description:
A positive integer m is said to a pure number if and only if m can be
expressed as q-th power of a prime p (q >= 1). Here your job is easy,
for a given positive integer k, find the k-th pure number.
Input:
The input consists of multiple test cases. For each test case, it
contains a positive integer k (k<5,000,000). Process to end of file.
Output:
For each test case, output the k-th pure number in a single line. If
the answer is larger than 5,000,000, just output -1.
Sample input:
1
100
400000
Sample output:
2
419
-1
Original page: http://acm.whu.edu.cn/learn/problem/detail?problem_id=1092
Can anyone give me some suggestion on the solution to this?
You've already figured out all the pure numbers, which is the tricky part. Sort the ones less than 5 million and then look up each input in turn in the resulting array.
To optimize you need to efficiently find all primes up to 5 million (note q >= 1 in the problem description: every prime is a pure number), for which you will want to use some kind of sieve (sieve of Erathosthenes will do, look it up).
You could probably adapt the sieve to leave in powers of primes, but I expect that it would not take long to sieve normally and then put the powers back in. You only have to compute powers of primes p where p <= the square root of 5 million, which is 2236, so this shouldn't take long compared with finding the primes.
Having found the numbers with a sieve, you no longer need to sort them, just copy the marked values from the sieve to a new array.
Having now looked at your actual code: your QuickSort routine is suspect. It performs badly for already-sorted data and your array will have runs of sorted numbers in it. Try qsort instead, or if you're supposed to do everything yourself then you need to read up on pivot choice for quicksort.
Try following approach:
static void Main(string[] args)
{
int max = 5000000;
int[] dp = new int[max];
for (int i = 2; i < max; i++)
{
if (dp[i] == 0)
{
long t = i;
while (t < max)
{
dp[t] = 1;
t *= i;
}
int end = max / i;
for (int j = 2; j < end; j++)
if (dp[i * j] == 0)
dp[i * j] = 2;
}
}
int[] result = new int[348978];
int pointer = 1;
for (int i = 2; i < max; i++)
{
if (dp[i] == 1)
result[pointer++] = i;
}
}
Into array as "1" marked pure numbers.
As "2" marked non pure(prime) numbers.
For each output check array ranges if it inside output result[index] if not output should be -1.

i can't figure out the bug in my program for calculating permutations

#include<stdio.h>
#include<conio.h>
main()
{
int i,j,k,x,y,n=4,a[]={1,2,3,4}; //n is the length of the array
for(i=0;i<n;i++)
{
for(k=0;k<(n-2);k++)
{
for(j=(n-1-k);j>=1;j--)
{
y=a[j];
a[j]=a[j-1];
a[j-1]=y;
for(x=0;x<n;x++)
{
printf("%d",a[x]);
}
printf("\t");
}
}
}
getch();
}
Some additional material (I'm a bit drunk, I will probably have to re-edit this tomorrow, so take it with a grain of salt):
Knuth and Sedgewick both covered permutations aeons ago.
Have a look at: http://www.princeton.edu/~rblee/ELE572Papers/p137-sedgewick.pdf
For n items you have n! permutations, so for 13 items you already have 6 227 020 800 permutations. So creating all permutations for a large set of items will become impossible pretty fast.
There are basically two sets of algorithms to create permutations, ranking/unranking and incremental change methods.
With ranking/unranking you have two methods rank and unrank.
Rank will give you the position of a permutation in the genereration order.
Unrank will give you the permutation that lies at integer m, with 0 >= m <= n! and n the amount of items you want to create permutations for.
This is useful for a variety of cases such as:
Creating a random permutation (you just create a random number from 0 to n! and call unrank(randomNumber)) and get the permutation at position randomNumber.
Creating sequences, getting the next permutation: You have a permutation p and call Rank(p) then Unrank(rank+1).
Incremental change methods:
These basically work through swapping and are more efficient than ranking/unranking:
From wikipedia, unordered generation:
function permutation(k, s) {
for j = 2 to length(s) {
swap s[(k mod j) + 1] with s[j]; // note that our array is indexed starting at 1
k := k / j; // integer division cuts off the remainder
}
return s;
}
Change this:
for(k=0;k<(n-2);k++)
to this:
for(k=0;k<(n-1);k++)
Also, try using more descriptive variable names...
I don't know the point of your program, but you may try to read the implementation of std::next_permutation. Generating all permutations with loops is somewhat tricky and I prefer using recursion.

Resources