Possible Spoiler Warning
I've spent ages trying to improve this algorithm and work out what's going wrong, but I can't seem to work out why the outputted answer is incorrect.
I'm trying to solve Project Euler #12 , to get the lowest triangular number to have over 500 divisors, but it says my answer is incorrect.
Here is my Python code:
import time
# function to get the number of divisors
def div(n):
d=2
for i in range(2,int(n**.5)+2):
if (n % i) == 0:
d += 1
return d
start = time.time()
w = True
n=m=1
while w:
n += 1
s = (n*(n+1))/2 # nth triangle number
r = div(s)
if r > m:
m = r
print s,"has",r,"divisors"
if r > 500:
w = False
print "Solved in",((time.time()-start)*1000),"milliseconds"
And the output for that code is this (in 66 seconds):
3 has 2 divisors
6 has 4 divisors
36 has 6 divisors
120 has 9 divisors
...
76576500 has 289 divisors
103672800 has 325 divisors
236215980 has 385 divisors
842161320 has 513 divisors
Solved in 65505.5799484 milliseconds
However, if I input 842161320 into the Project Euler problem, it says it's incorrect.
What am I doing wrong?
I see two bugs:
div
function is broken: div(24) == 5
, while it should be 8 3
, although it should be 1
You could implement a working div
like this:
import math
def divisors(n):
return sum(1 for x in range(1, n+1) if n % x == 0)
Also, that code is inefficient as hell, some suggestions to improve it are:
Instead of calculating the n
th triangular number using your formula, use a rolling sum:
import itertools
s = 0
for i in itertools.count(1):
s += i
if div(s) > 500:
print s
break
Also, Use prime factors to calculate the number of divisors . You can create a prime factor cache for maximum performance.
You are undercounting the total number of divisors. 36, for example, has 9 divisors: 1,2,3,4,6,9,12,18,36. It's true the algorithm only needs to test numbers smaller than sqrt(n)
to find all divisors, but you still need to include the implied "large" divisors in your count.
With the help of Niklas, and changing my div
method, I've got the answer. Also, it's now only takes 8% of the time my previous algorithm took.
The algorithm now looks like this:
import time
import itertools
def div(n):
d=0
for i in range(1,int(n**.5)+1):
if (n % i) == 0:
d += 1
return 2*d
start = time.time()
s = m = 0
for i in itertools.count(1):
s += i
r = div(s)
if r > m:
m = r
print s,"has",r,"factors"
if div(s) > 500:
break
print "Solved in",((time.time()-start)*1000),"milliseconds"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.