Speeding up Euler Pr 12

Please support our C advertiser: Programming Forums - DaniWeb Sister Site
Thread Solved

Join Date: Jun 2008
Posts: 255
Reputation: Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough 
Solved Threads: 16
Hiroshe's Avatar
Hiroshe Hiroshe is offline Offline
Posting Whiz in Training

Speeding up Euler Pr 12

 
0
  #1
Jun 29th, 2009
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.
Last edited by Hiroshe; Jun 29th, 2009 at 10:26 pm. Reason: Forgot attachment
Attached Files
File Type: c triangle.c (9.1 KB, 1 views)
"Sometimes, when I lie in bed at night and look up at the stars, I think to myself, "Man! I really need to fix that roof."-Jack Handy
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 255
Reputation: Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough 
Solved Threads: 16
Hiroshe's Avatar
Hiroshe Hiroshe is offline Offline
Posting Whiz in Training

Re: Speeding up Euler Pr 12

 
0
  #2
Jun 29th, 2009
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?
"Sometimes, when I lie in bed at night and look up at the stars, I think to myself, "Man! I really need to fix that roof."-Jack Handy
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 255
Reputation: Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough 
Solved Threads: 16
Hiroshe's Avatar
Hiroshe Hiroshe is offline Offline
Posting Whiz in Training

Re: Speeding up Euler Pr 12

 
0
  #3
Jun 29th, 2009
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.
"Sometimes, when I lie in bed at night and look up at the stars, I think to myself, "Man! I really need to fix that roof."-Jack Handy
Reply With Quote Quick reply to this message  
Join Date: Sep 2008
Posts: 1,595
Reputation: BestJewSinceJC is a name known to all BestJewSinceJC is a name known to all BestJewSinceJC is a name known to all BestJewSinceJC is a name known to all BestJewSinceJC is a name known to all BestJewSinceJC is a name known to all 
Solved Threads: 202
BestJewSinceJC BestJewSinceJC is offline Offline
Posting Virtuoso

Re: Speeding up Euler Pr 12

 
0
  #4
Jun 30th, 2009
I actually don't understand the pattern. Enlighten me.
Out.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 255
Reputation: Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough Hiroshe is a jewel in the rough 
Solved Threads: 16
Hiroshe's Avatar
Hiroshe Hiroshe is offline Offline
Posting Whiz in Training

Re: Speeding up Euler Pr 12

 
0
  #5
Jun 30th, 2009
Originally Posted by BestJewSinceJC View Post
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.
"Sometimes, when I lie in bed at night and look up at the stars, I think to myself, "Man! I really need to fix that roof."-Jack Handy
Reply With Quote Quick reply to this message  
Join Date: May 2009
Posts: 5
Reputation: O71v13r is an unknown quantity at this point 
Solved Threads: 0
O71v13r O71v13r is offline Offline
Newbie Poster
 
-1
  #6
Oct 21st, 2009
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, ...
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 33
Reputation: SVR is an unknown quantity at this point 
Solved Threads: 4
SVR SVR is offline Offline
Light Poster
 
0
  #7
Oct 23rd, 2009
Originally Posted by Hiroshe View Post
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.
Last edited by SVR; Oct 23rd, 2009 at 2:03 am.
Attached Files
File Type: c triangle.c (11.2 KB, 1 views)
Reply With Quote Quick reply to this message  
Reply

This thread has been marked solved.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC