I chose to do these Project Euler problems in C because I was under the impression that C is fast, but that doesn't seem to be the case. Both of the following loops are extremely slow:
int problem_7 () {
int n = 0;
for (int i = 1; i <= 10001; i++) {
for (int j = (i==1)?1:n+1; j > 0; j++) {
int factorCounter = 0;
for (int k = 1; k <= j/2; k++)
factorCounter += (j % k == 0);
if (factorCounter == 1) {
n = j;
break;
}
}
}
return n;
}
long long int problem_10 () {
long long int sum = 0;
for (int i = 2; i < 2000000; i++) {
int factorCount = 0;
for (int j = 1; j <= i/2; j++) {
factorCount += (i % j == 0);
sum += i*(j == i/2 && factorCount == 1);
}
}
return sum;
}
Is there any way I can make these loops run faster? They do what they're supposed to do, but they each take like 5 minutes to execute.
With branch prediction using boolean numeric values is not as needed:
Looking at problem7 for example, this can be sped up by using if statements:
int n = 0;
for (int i = 1; i <= 10001; i++) {
for (int j = (i==1)?1:n+1; j > 0; j++) {
int factorCounter = 0;
for (int k = 1; k <= j/2; k++)
{
if (j%k==0) // code is changed HERE
{
factorCounter ++;
if (factorCounter > 1)
{
break;
}
} // code change ends here
}
if (factorCounter == 1) {
n = j;
break;
}
}
This completes in 0.88secs as opposed to the original's 9.5secs -- over 10 times faster from that one change
Explanation of optimization and rational for equivalence:
The change made was from the original line:
factorCounter += (j % k == 0);
First change that to its equivalent:
if (j%k==0)
{
factorCounter ++;
}
Notice how factorCounter can only increment, and after the loop any value over 1 is discarded because (factorCounter == 1) will be false, so once it is greater than 1, there is no reason to continue the loop. Also notice that the value of factorCounter can only be changed when (j%k==0) so the test for factorCounter > 1 should occur inside the if check, the code is now:
if (j%k==0)
{
factorCounter ++;
if (factorCounter > 1)
{
break; // We stop the loop much earlier HERE
}
}
And exiting the loop early is what gives the performance gain
I guess I'll make this an answer. Your program is slow because your loops are poorly designed and poorly nested. I'm not going to do a complexity analysis, but you're somewhere in the range of O(N^x) where x > 4 (from what I can tell).
It's just bad programming and it has little to do with loop optimization. You need to use something like the Sieve of Eratosthenes to solve Euler 7. I won't give you the solution here, as with the Wiki article it's fairly trivial to solve.
C is fast. Higher level languages can be fast as well. But even the best compiler can't optimize out the extra operations you're having it do! A simple way to reduce number of operations in your problem 7 algorithm would be to break the deepest for loop if factorCounter becomes greater than 1. Sorry to break it to you but: it's not the compiler it's the algorithm!
A more direct approach to the problem executes almost immediately. You don't really need that many optimizations.
#include <iostream>
#include <cmath>
using namespace std;
bool isPrime(int j)
{
for(int fac = 2; fac < sqrt(j)+0.5; ++fac)
if(j%fac == 0)
return false;
return true;
}
int main()
{
int primesFound = 1; // 2 is prime
int possiblePrime = 1;
while(primesFound != 10001)
{
possiblePrime += 2;
if(isPrime(possiblePrime))
++primesFound;
}
cout << possiblePrime << endl;
}
Related
How can i write a program that lists all sexy prime pairs that exist in n numbers.
For example if n = 10 the output should be (5, 11) and (7, 13)
My idea was to generate all primes within n and then add 6 to each and check if the i + 6 is a prime. But it doesnt work, there's no output and the program ends.
#include <stdio.h>
int main() {
int i, j, n, k, isprime = 1, prime2, flag = 0;
scanf("%d", &n);
for (i = 3; i <= n; i++){
for (j = 2; j <= i; j++){
if (i % j == 0)
break;
}
if (i == j){
prime2 = i + 6;
for (k = 3; k <= prime2; k++){
if (prime2 % k == 0){
flag++;
break;
}
}
if (flag == 0){
printf("%d %d\n", i, prime2);
}
}
}
return 0;
}
Any ideas of what im doing wrong or any tips on how to solve it? (with loops only)
As there're a lot of resources about finding a prime number, I'm not going to discuss that. Rather I'll try to point out the bug in your code.
First problem:
for (k = 3; k <= prime2; k++)
Here you need to run the loop till prime2 - 1. Also you should start checking from 2 rather than 3, just like you did previously. That means,
for (k = 2; k < prime2; k++)
or
for (k = 2; k <= prime2 - 1; k++)
Reason: when k = prime2, prime2 % k will be 0. For finding out whether a number is prime we don't need to check if that number is divisible by 1 and that number itself.
Note: Now you might think why the first prime number loop for (j = 2; j <= i; j++) is working .
It's working because you've given an additional condition if (i == j) after it.
Second problem:
You need to declare the flag variable within the first loop.
for (i = 2; i <= n; i++)
{
int flag = 0;
.... (rest of the code)
....
}
Reason: Basically with the flag value, you're trying to find out whether prime2 is a prime number.
Every time you'll get a prime number from the first loop, you'll have a new value of prime2. In your code, once you're incrementing the value of flag, you're never resetting the flag value.
That's why once your code detects a prime2 which is not a prime, it'll never detect the second prime number again (prime2 which is actually prime).
Overall code:
#include <stdio.h>
int main()
{
int i, j, n, k, isprime = 1, prime2;
scanf("%d", &n);
for (i = 3; i <= n; i++)
{
int flag = 0; // changing point
for (j = 2; j <= i; j++)
{
if (i % j == 0)
break;
}
if (i == j)
{
prime2 = i + 6;
for (k = 2; k < prime2; k++) // changing point
{
if (prime2 % k == 0)
{
flag++;
break;
}
}
if (flag == 0)
{
printf("%d %d\n", i, prime2);
}
}
}
return 0;
}
Few resources to know more about finding out prime numbers:
Prime Numbers
C Program to Check Whether a Number is Prime or not
Sieve of Eratosthenes
You can use Sieve to speed up the program. It can generate all pairs in O(N log N) time. Here's the Algorithm.
Now, you have a boolean array, is_prime where is_prime[i] is true if i is a prime, false otherwise.
Now, iterate from i = 1 to i = N and check if is_prime[i] && is_prime[i + 6], if the condition is true, output the pair.
So here is the problem: Write a program that accept an integer n, print out the largest number but smaller or equal n that is the product of two consecutive even number. Example: Input: 12, Output: 8 ( 2x4 )
Here is my code :
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
for (int i = n; i >= 0; i--)
{
for (int j = 0; j <= n; j = j + 2)
{
if ( i == j * (j+2) )
{
printf("%d ", i);
break;
}
}
}
return 0;
}
So if i input 20, it will print out 8 and 0 instead of 8, if i input 30, it will print out 24,8 and 0 instead of just 24. How do i make it stop after printing out the first number that appropriate ?
You need to stop an outer loop from processing, for example by using a boolean flag (meaning "solution found, we finish work") or a goto statement.
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int solutionFound = 0;
for (int i = n; i >= 0; i--) {
// this could also be put into for's condition i.e. "i >= 0 && !solutionFound"
if (solutionFound) {
break;
}
for (int j = 0; j <= n; j = j + 2) {
if ( i == j * (j+2) ) {
printf("%d ", i);
solutionFound = 1;
break;
}
}
}
return 0;
}
EDIT: immediate return as noted in the comments is also a nice idea, if you don't need to do anything later.
Your problem is that you are nested - in a for loop which is inside another for loop - when you want to stop processing.
Some languages would let you code break 2; to indicate that you want to break out of 2 loops. Alas, C i snot such a language.
I would recommend that you code a function. That would serve a few porpoises: 1) your main should be "lean & mean" 2) as your programs get larger, you will learn the benefits of putting individual coding tasks into functions 3) you can use return; instead of break; and it will exit the function immediately.
Something like this:
#include <stdio.h>
void FindNeighbouringDivisors(int n)
{
for (int i = n; i >= 0; i--)
{
for (int j = 0; j <= n; j = j + 2)
{
if ( i == j * (j+2) )
{
printf("%d times %d = %d", j, j + 2, i);
return;
}
}
}
printf("There are no two adjacent even numbers which can be multiplied to give %d", n);
}
int main()
{
int n;
scanf("%d", &n); /* could get from comamnd line */
FindNeighbouringDivisors(n);
return 0; /* should be EXIT_SUCCESS */
}
Btw, when you have a problem with your code, ask a question here. When you have it working, consider posting it at our code review site where more experienced programmers can give you advice on how to improve it. It's a great way to learn
Break only breaks you out of immediate loop, so either use flags or just use return to terminate the execution. Or you can even use following code:
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
for (int j = 0; j <= n; j = j + 2)
{
if ( n < j * (j+2) )
{
printf("%d ", j*(j-2));
break;
}
}
return 0;
}
#include <stdio.h>
int f(int (*d)[2], int n)
{
int p = 0, cnt;
for (int i=2; i*i <= n; ++i)
{
for (cnt = 0; n % i == 0; cnt++, n /= i) {}
if (cnt == 0)
continue;
d[p][0] = i;
d[p++][1] = cnt;
}
if (n > 1)
{
d[p][0] = n;
d[p++](l] = 1;
}
return p;
}
So as far as I understand when I m looking for complexity, I m looking for loops. The first loop is trivial. It gives us O(sqrt(n)), but there is a second loop which decreases n, I don t really understand this moment. Experiments show that complexity is O(log(n)).
Speaking of the second loop : n % i == 0; and n=n/i; if we loop in the for loop we will have in the first iteration n=n/i/i .... in the k iteration we are going to have n/(i^k) and this will stop when n%i!=0; lets say n/(i^k)==1 so 1%i==1 !=0 so from n/(i^k)==1 we are going to have k=log(n) in i base which mean log(n)
I am writing a program in c to store 2^100000, and I am using arrays to store the result.
Here is the full code:
#include <stdio.h>
#include <math.h>
int main()
{
int test, n, i, j, x, resul;
int a[200], m, temp;
scanf("%d", &test);
for (i = 0; i < test; i++) {
a[0] = 3; // initializes array with only 1 digit, the digit 1.
m = 1; // initializes digit counter
scanf("%d", &n);
temp = 0; // Initializes carry variable to 0.
for (i = 1; i < n; i++) {
for (j = 0; j < m; j++) {
x = a[j] * 2 + temp; //x contains the digit by digit product
a[j] = x % 10; //Contains the digit to store in position j
temp = x / 10; //Contains the carry value that will be stored on later indexes
}
while (temp > 0) { //while loop that will store the carry value on array.
a[m] = temp % 10;
temp = temp / 10;
m++; // increments digit counter
}
}
for (i = m - 1; i >= 0; i--) //printing answer
printf("%d", a[i]);
}
return 0;
}
Can some one tell me a more efficient way to do so to reduce the time complexity?
2^n in binary is an (n+1)-digit integer with every bit set to 0 except the most significant bit being set to 1. e.g: 32 = 2^5 = 0b100000
Likewise, 2^100000 can be computed by setting the 100001-th bit in a zeroed 100001 bit long integer to 1. O(1) is as time efficient as you can go.
There are several problems with your code:
The array a is defined with a size of only 200 digits. This is much too small for 2^100000 that has 30103 digits. You should increase the array size and check for overflow in the multiplication algorithm.
You initialize a[0] = 3; and comment this as the digit 1. Indeed you should write a[0] = 1;.
The second loop for (i = 1; i < n; i++) should include the desired power number: you should write for (i = 1; i <= n; i++).
You use the same loop variable for the outer loop and the second level ones, causing incorrect behavior.
You do not test the return value of scanf, causing undefined behavior on invalid input.
You do not check for overflow, invoking undefined behavior on large values.
Here is a corrected version:
#include <stdio.h>
int main()
{
int n, i, j, x, m, test, temp;
int a[32000];
if (scanf("%d", &test) != 1)
return 1;
while (test-- > 0) {
if (scanf("%d", &n) != 1)
break;
a[0] = 1; // initializes array with only 1 digit, the number 1.
m = 1; // initializes digit counter
temp = 0; // Initializes carry variable to 0.
for (i = 1; i <= n; i++) {
for (j = 0; j < m; j++) {
x = a[j] * 2 + temp; //x contains the digit by digit product
a[j] = x % 10; //Contains the digit to store in position j
temp = x / 10; //Contains the carry value that will be stored on later indexes
}
// while loop that will store the carry value on array.
if (temp > 0) {
if (m >= (int)(sizeof(a)/sizeof(*a)))
break;
a[m++] = temp;
temp = 0;
}
}
if (temp > 0) {
printf("overflow");
} else {
for (i = m - 1; i >= 0; i--) //printing answer
putchar('0' + a[i]);
}
printf("\n");
}
return 0;
}
Running this code with input 1 and 100000 on my laptop takes about 6,5 seconds. That's indeed quite inefficient. Using a few optimization techniques that do not really change the complexity of this simple iterative algorithm still can yield a dramatic performance boost, possibly 100 times faster.
Here are some ideas:
store 9 digits per int in the array instead of just 1.
multiply by 2^29 in each iteration instead of just 2, using long long to compute the intermediary result. Initialize the first step to 1 << (n % 29) to account for n not being a multiple of 29. 2^29 is the largest power of 2 less than 10^9.
Here is version that implements these two ideas:
#include <stdio.h>
int main() {
int n, i, j, m, test, temp;
int a[32000];
if (scanf("%d", &test) != 1)
return 1;
while (test-- > 0) {
if (scanf("%d", &n) != 1)
break;
i = n % 29;
n /= 29;
a[0] = 1 << i;
m = 1;
temp = 0;
for (i = 1; i <= n; i++) {
for (j = 0; j < m; j++) {
long long x = a[j] * (1LL << 29) + temp;
a[j] = x % 1000000000;
temp = x / 1000000000;
}
if (temp > 0) {
if (m >= (int)(sizeof(a)/sizeof(*a)))
break;
a[m++] = temp;
temp = 0;
}
}
if (temp > 0) {
printf("overflow");
} else {
printf("%d", a[m - 1]);
for (i = m - 2; i >= 0; i--)
printf("%09d", a[i]);
}
printf("\n");
}
return 0;
}
Running it on the same laptop computes the correct result in only 33ms, that's 200 times faster.
The Time Complexity is the same, but implementation is much more efficient.
Be aware that native C integers are limited, in practice to some power of two related to the word size of your computer (e.g. typically 32 or 64 bits). Read about <stdint.h> and int32_t & int64_t.
Maybe you want some bignums (or bigints), a.k.a. arbitrary precision arithmetic.
The underlying algorithms are very clever (and more efficient than the naive ones you learned in school). So don't try to reinvent them, and use a library like GMPlib
I implement Sieve of eratosthenes and it works fine. But if I increase the MAX value to something like 50000 the Application crash with a unhandled win32 exception. I think this happened because of a stackoverflow.
Now my Question is how do I prevent this?
#define MAX 50000
void Sieb_des_Eratosthenes()
{
char Zahlen[MAX + 1] = {0};
int i, j, x;
for(i = 2; i <= MAX; i++)
{
if(Zahlen[i] == 0)
{
Zahlen[i] = 1;
for(j = i * i; j <= MAX; j += i)
{
Zahlen[j] = -1;
}
}
}
}
My idea was to allocate memory but this doesn't work
#define MAX 50000
int Sieb_des_Eratosthenes()
{
int i, j, x;
char *array;
array = malloc((MAX + 1) * sizeof(*array));
if (array==NULL) {
printf("Error allocating memory!\n");
return -1; //return with failure
}
for(i = 2; i <= MAX; i++)
{
if(array[i] == 0)
{
array[i] = 1;
for(j = i * i; j <= MAX; j += i)
{
array[j] = -1;
}
}
}
}
The original problem in your function failing is in this for loop.
for(j = i * i; j <= MAX; j += i)
when i gets equal or larger than 46349 the result i * i overflows and j gets the value of -2146737495 and then fails at Zahlen[j] = -1;
While all the other answers are true wrt. the actual cause (integer overflow), you simply missed some implementation details provided by the pseudo code in the wiki. The following works:
Use calloc to allocate the memory. Then, all values are initialized to 0 which means true in the sense of the wiki pseudo code.
In the outer loop, only loop until sqrt(MAX) - see the pseudo code in the wiki article.
In the inner loop, mark all multiples of i with 1 (false in the sense of the wiki pseudo code).
for(i = 2; i <= sqrt(MAX); i++) {
if(array[i] == 0) { // "true"
for(j = i*i; j <= MAX; j += i) {
array[j] = 1; // "false"
}
}
}
Then, all elements which are still 0 are prime numbers.
In addition, it is not necessary to use (signed) int - all numbers are positive, so you should use unsigned int.
With this approach, you should be able to use the whole range of an unsigned int for the MAX value (up to 4294967295 if unsigned int is 32 bit)
an int can only hold a max of -2^31 to 2^31:
http://en.wikipedia.org/wiki/Integer_(computer_science)
your overflowing the int