Reputation: 929
I'm working on Project Euler problem 12
What is the value of the first triangle number to have over five hundred divisors?
I know for certain that it can produce correct answers for smaller numbers. For example if I replace > 500
with == 6
, the output result I get is an expected 28
.
For 500 divisors, about two minutes into the execution, the program begins to run very slowly. I believe every variable here is being overwritten at each iteration. Why is it slow? I have tried separating into functions to make use of local variables, but this doesn't improve the running time.
Code:
import sys
currentNumber, currentCalculationNumber, divisorCount, naturalNumber = 1, 1, 0, 1
while True:
while currentCalculationNumber <= currentNumber:
if currentNumber % currentCalculationNumber == 0:
divisorCount += 1
currentCalculationNumber += 1
if divisorCount > 500:
print ("ANSWER: " , currentNumber)
sys.exit(0)
naturalNumber += 1
currentNumber += naturalNumber
currentCalculationNumber, divisorCount = 1, 0
Upvotes: 0
Views: 180
Reputation: 8378
I agree with @Prune's answer but here is a faster version of your brute-force algorithm:
import numpy as np
i = 1
f = lambda N: (N * (N + 1)) // 2
ndmax = 0
while True:
t = f(i)
p = np.arange(1, t + 1)
r = np.mod(t, p)
nd = p.size - np.count_nonzero(r) + 1
if nd > ndmax: # track progress
ndmax = nd
print((i, t, nd))
if nd > 500:
print ("ANSWER: " , t)
break
i += 1
divisor_count
)from sympy import divisor_count
import numpy as np
i = 1
f = lambda N: (N * (N + 1)) // 2
ndmax = 0
while True:
t = f(i)
nd = divisor_count(t)
if nd > ndmax: # track progress
ndmax = nd
print((i, t, nd))
if nd > 500:
print ("ANSWER: " , t)
break
i += 1
For more details see divisor_count
and reference therein.
Upvotes: 1
Reputation: 77860
The slowness is from your brute-force method of counting divisors. The solution is on the order of 10^8, so you're iterating through that inner while
loop on the order of 10^16 times: the nested loops make an O(n) process. This is going to take a while. You need something more efficient, at least O(n log(n) ).
One of the purposes of Project Euler is to get us to investigate more efficient algorithms. For this one, you'll likely want to use the divisor function, which will require any of the numerous prime-generation functions.
You should develop a "bag of tricks" module that you import
for most problems. In fact, you should already have one that generates prime numbers, from earlier problems (assuming that you're attacking them in some order). If not, try this one.
Upvotes: 3