944,191 Members | Top Members by Rank

Ad:
  • C Discussion Thread
  • Marked Solved
  • Views: 708
  • C RSS
Jun 29th, 2009
0

Speeding up Euler Pr 12

Expand Post »
Can anyone help me with doing problem 12 on project euler? The question is asking which triangle number has more than 500 factors. The first few triangle numbers are: 1, 3, 6, 10, 15, 21, 28 ... Hope you understand the pattern, cause a can't explain it in words vary well.

Anyways I written the code in C, and it's just too slow. Here's an english version I wrote for easyness:
  1. Generate the triangle number under (500^2)
  2.  
  3. loop until the triangle number's factors is more than 500
  4. generate next triangle number
  5.  
  6. return triangle number
  7.  
  8. to find how many factors a number has:
  9. divide number by prime number going from lowest to higher until it divides evenly
  10. if the result is prime, tally the prime number and the result
  11. if the result is not prime, tally the prime number and the result becomes the number and loop back to the "divide number by pr..." stage
  12. add 1 and multiply everything in the tally that is not zero
  13. the product is the number of factors
  14.  
  15. to generate prime numbers:
  16. start with 2 and 3
  17. int n = 1, prime = 0
  18. while prime is not prime
  19. increase n if called on an odd time
  20. loop back with prime = 6n-1 on every odd time and
  21. loop back with prime = 6n+1 on every even time
  22. return prime
  23.  
  24. and finally to check if a number is prime:
  25. if number is under 2, its not prime
  26. //this is a prime sieve
  27. if number is 2, its prime
  28. if number is divisible by 2, its not prime
  29. if number is 3, its prime
  30. if number is divisible by 3, its not prime
  31. ...
  32. int count = what ever last sieve was
  33. while count < sqrt number
  34. if number mod count = 0
  35. return 0 (not prime)
  36. return 1 (is prime)
  37.  

I'm going to attach the c version becouse its 341 lines long!

I think the time is being waisted mostly at the isprime step, or the countdiv (factoring) step.

Any suggestions to speed this puppy up? Thanks alot.
Attached Files
File Type: c triangle.c (9.1 KB, 12 views)
Last edited by Hiroshe; Jun 29th, 2009 at 10:26 pm. Reason: Forgot attachment
Similar Threads
Reputation Points: 431
Solved Threads: 17
Posting Whiz in Training
Hiroshe is offline Offline
255 posts
since Jun 2008
Jun 29th, 2009
0

Re: Speeding up Euler Pr 12

Hmm. Just had an idea (about 5 minutes after posting the above). Maybe the thing that slowing it down is the part where it reads the array. Look at function countdiv() I guess I could return the highest prime factor so it knows not to loop past it. Any other idea's?
Reputation Points: 431
Solved Threads: 17
Posting Whiz in Training
Hiroshe is offline Offline
255 posts
since Jun 2008
Jun 29th, 2009
0

Re: Speeding up Euler Pr 12

Still room for inprovement, but I got it working a reasonalble speed.. I think I kinda solved this thread on my own, but if there are any other suggestion's, I'm still interested in making my code faster.
Last edited by Hiroshe; Jun 29th, 2009 at 10:55 pm.
Reputation Points: 431
Solved Threads: 17
Posting Whiz in Training
Hiroshe is offline Offline
255 posts
since Jun 2008
Jun 30th, 2009
0

Re: Speeding up Euler Pr 12

I actually don't understand the pattern. Enlighten me.
Reputation Points: 874
Solved Threads: 352
Posting Maven
BestJewSinceJC is offline Offline
2,758 posts
since Sep 2008
Jun 30th, 2009
0

Re: Speeding up Euler Pr 12

I actually don't understand the pattern. Enlighten me.
Err.. try understanding this (not tested):
  1. int count = 1;
  2. int triangle = 1;
  3. while(1) {
  4. printf("%d\n", triangle);
  5. count++;
  6. triangle += count;
  7. }
You add 1 more than you did the last time starting a 1, 1+2, 3+3, 6+4... See I really can't explain it good
Last edited by Hiroshe; Jun 30th, 2009 at 12:23 pm.
Reputation Points: 431
Solved Threads: 17
Posting Whiz in Training
Hiroshe is offline Offline
255 posts
since Jun 2008
Oct 21st, 2009
-1
Re: Speeding up Euler Pr 12
Perhaps this explanation can help you out BestJewSinceJC:

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be: 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Reputation Points: 16
Solved Threads: 0
Newbie Poster
O71v13r is offline Offline
5 posts
since May 2009
Oct 23rd, 2009
0
Re: Speeding up Euler Pr 12
Click to Expand / Collapse  Quote originally posted by Hiroshe ...
Still room for inprovement, but I got it working a reasonalble speed.. I think I kinda solved this thread on my own, but if there are any other suggestion's, I'm still interested in making my code faster.
The first improvement I found was that you don't need to regenerate all the primes every time. Split the array into separate arrays. One global array of primes and one for factor counts.

This improved from ??? to 10 mins or so.
I don't know how long it originally took, I killed it after a while.

To make it work change the fillprimes function to just fill the next x primes ...

  1. void fillprime( int maxPrime ) {
  2. /* This function fills the second dimention of an array with primes. It uses the
  3. modified version of problem 2 attemp 2's 'nextprime' and 'isprime' used in
  4.   problem 7. Why do all these's questions rely on prime numbers? */
  5.  
  6. static int c = 0, n = 0;
  7.  
  8. do {
  9. primes[primeCount] = nextprime(&n, &c);
  10. }while(primes[primeCount++] <= maxPrime);
  11.  
  12. }

You see I changed the test to maxPrime and test the prime value instead of the count.
Now everywhere you loop over the array(s) you only loop until maxPrime is reached.

Next is findprimefactor. You call tally which iterated through the entire array again. Now as you are iterating over the prime array you have the index of the factor to increment.

  1. void findprimefactor(int number, int *output) {
  2. /* This function will find all of the prime factors. It works by dividing number
  3. by primes until it evenly divides. That prime is a prime factor, and if the
  4. result is also prime, its is a prime factor. If the result is not a prime
  5.   factor, it becomes the new 'number'. */
  6.  
  7. int n = 0;
  8. int p = 0;
  9. int n1 = 0;
  10.  
  11. while(n<primeCount)
  12. {
  13. p = primes[n];
  14. if(number == p) { /* if result is 1 */
  15. output[n]++; /* Add that 'number' to its place on first dim */
  16. return;
  17. }
  18.  
  19. if( (number % p) ==0) { /* number evenly divides into p */
  20. output[n]++; /* Add that 'p' to its place on first dim */
  21. number /= p;
  22. n1 = findPrime(number);
  23.  
  24. if(n1 != -1) { /* if result is prime */
  25. output[n1]++; /* Add result to its place on first dim */
  26. return;
  27. }
  28. /* if result is not prime */
  29. /* The result is the new number */
  30. n = 0;
  31. }
  32. else
  33. n++;
  34. }
  35.  
  36. // should not get here except on 1
  37. if(number>0)
  38. {
  39. printf("\nRemainder - %d",number);
  40. }
  41. return;
  42. }

When it checks the result of the division it could just continue as if it isn't prime. That would be the same as the search done in isprime. But a quick binary search across the existing primes works even better.
The binary search code came outta my head so it probably has holes. But it worked for the few values I tested.

Now the time was reduced to around 5 mins.

I tweaked a few standard things without much speed up.

Then the biggie ... to get the factors to come out right you have to gen primes all the way up to 'number'. But for most things you only need primes up to sqrt(number) +1.

The only time you really need all is if number is prime. Hmmm... all primes only have to factors. No need to factor or count primes at all!

  1. int countdiv( int number) {
  2. /* This function returns the number of divisors. It finds the prime divisors,
  3. adds 1 to each, and finds the product of all of them. It returns the product.
  4. */
  5.  
  6. int count = 0;
  7. int product = 1;
  8. int maxPrime;
  9.  
  10.  
  11. if(isprime(number) )
  12. {
  13. return 2;
  14. }
  15.  
  16. maxPrime= (int) sqrt(number)+1;
  17.  
  18. fillprime(maxPrime); /* generate next x primes */
  19.  
  20. init(primeCount, primefactor); /* clear count array array with 0's */
  21. findprimefactor(number, primefactor); /* count each prime factor */
  22.  
  23.  
  24. while(primes[count] <= maxPrime) {
  25. if(primefactor[count] != 0) /* If there is a number of that prime */
  26. product *= (primefactor[count]+1); /* add 1 and multiply */
  27. count++;
  28. }
  29.  
  30. return product;
  31. }

Boom! It takes less than a second to calculate the first 500 term triangle.

I've attached the changed file.
Attached Files
File Type: c triangle.c (11.2 KB, 11 views)
Last edited by SVR; Oct 23rd, 2009 at 2:03 am.
SVR
Reputation Points: 10
Solved Threads: 4
Light Poster
SVR is offline Offline
44 posts
since May 2008

This thread is solved

Either the thread starter or a moderator has marked this thread as solved. You can most likely trust the responses and answers given. There is most likely no reason for any further responses to be posted here. If you have a related question, please start a new thread in this forum instead.

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C Forum Timeline: Reading all pair lines from a file and then putting them in another file
Next Thread in C Forum Timeline: Reading in From A File





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC