So I'm solving Problem 12 of Project Euler in Python. There's the task:
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, ...
Let us list the factors of the first seven triangle numbers:
1: 1 3: 1,3 6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28 We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five
hundred divisors?
I made 2 functions: first will generate triangle numbers infinitely:
def triangle_number(n_th_triangle, triangle_sum_number, triangle):
while True:
n_th_triangle += 1
while triangle_sum_number < n_th_triangle:
triangle_sum_number += 1
triangle += triangle_sum_number
print(triangle)
triangle_number(0, 0, 0)
second one will count, how many divisors has the given number:
def divisor_number(divisor, divisor_number, number):
while divisor < number:
divisor += 1
if number % divisor == 0:
divisor_number += 1
print(number)
print(divisor_number)
divisor_number(0, 0, *number*)
How to slap them together ? So that will be the solution of the 12 th problem on Project Euler.
Thanks!
First, you should return these values rather than print them.
As others have mentioned, using the yield keyword will allow you to return values to the caller without suspending function execution and deleting everything you already computed from the stack. Here is a pretty good tutorial on using generators in python.
Then, once you implement triangle_number() as a generator, you could have a simple loop such as the following:
tri_gen = triangle_number()
while(divisor_number(num)) <= 500:
num = next(tri_gen)
Some pointers:
you should yield the next triangle number instead of just printing it
you do not have to declare all internal variables as parameters
do not test all possible divisors, this will be much too slow
Instead, you can try the following:
calculate the first few thousand prime numbers using an efficient algorithm
use those to calculate the prime factorization of the number, e.g. [2, 5, 5] for 50; use divide an conquer and memoization to speed this up 1
finally, use the prime factorization to efficiently calculate the total number of divisors
Just for perspective, the result is a >> 10k-th triangle number and is somewhere around 75M.
1) As noted in comments you can use the fact that sum(1..n), and thus the n-th triangle number, is n(n+1)/2 and use that to find the prime factorization (and thus the divisors) much easier.
Related
I'm a beginner in programming, and I'm trying to practice Project Euler questions.
Question 23:
A perfect number is a number for which the sum of its proper divisors
is exactly equal to the number. For example, the sum of the proper
divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28
is a perfect number.
A number n is called deficient if the sum of its proper divisors is
less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the
smallest number that can be written as the sum of two abundant numbers
is 24. By mathematical analysis, it can be shown that all integers
greater than 28123 can be written as the sum of two abundant numbers.
However, this upper limit cannot be reduced any further by analysis
even though it is known that the greatest number that cannot be
expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as
the sum of two abundant numbers.
I got the correct answer by the following code:
list1=[]
list2=[]
for num in range(1,28123):
list1.append(num)
for num in list1:
sum1=1
for i in range (2,int(num**0.5)+1):
if not num%i:
sum1+=(i+(num/i))
if int(num**0.5)==(num**0.5):
sum1-=(num**0.5)
if sum1>num:
list2.append(num)
for i in range(len(list2)):
for j in range(i,len(list2)):
check=list2[i]+list2[j]
if check<28123:
list1[check-1]=0
print(sum(list1))
I tried to make a small modification to this code, by changing the definition of list1 by adding a '0' by the following code:
list1=[x for x in range (28123)]
list2=[]
for num in list1:
sum1=1
for factor in range (2,int(num**0.5)+1):
if not num%factor:
sum1+=(factor+(num/factor))
if int(num**0.5)==(num**0.5):
sum1-=(num**0.5)
if sum1>num:
list2.append(num)
for i in range(len(list2)):
for j in range(i,len(list2)):
check=list2[i]+list2[j]
if check<28123:
list1[check]=0
print(sum(list1))
As you can see, I also changed the second last line according the new indexes. But this changed my answer from 4179871 to 4178876. I can't understand why. The former is the correct answer.
I know my code is not very efficient as I'm a beginner, trying to improve. Help will be much appreciated!
Edit:
I tried to check if 0 is getting added into the abundant number's list2, but the following code gave me [] as an output, hence it wasn't.
num = 0
list2 = []
sum1 = 1
for i in range (2, int (num ** 0.5) + 1):
if not num % i:
sum1 += (i+ (num / i))
if int (num ** 0.5) == (num ** 0.5):
sum1 -= (num ** 0.5)
if sum1 > num:
list2.append(num)
print(list2)
You inserted 0; your code recognizes this as an abundant number.
Therefore, any abundant number that was previously not the sum of two others ... is suddenly the sum of itself and 0. It's excluded from the list.
I strongly recommend that you learn to perform basic logical debugging. I determined this with a simple insertion. I pasted both of your algorithms into a file. In between, I saved the results of the first algorithm:
...
print(sum(list1))
keep1 = list1
keep2 = list2
Then, after the second algorithm, I simply found the differences between the lists you formed in the two algorithms:
print("acquired abundant numbers", set(list2) - set(keep2))
print("lost summed numbers", set(keep1) - set(list1))
Output:
4179871
4178876
acquired abundant numbers {0}
lost summed numbers {945, 18, 12, 20}
... and there is the telling evidence: three numbers less than 24, which is stated as the lowest number qualifying for the summation. Each of these is abundant, and the first added output line shows that your code mis-allocated 0 as abundant.
This is one of the most basic debugging techniques: when you have a solid difference in expected and actual output, print or otherwise compare the intermediate values to find the point of difference.
You note that I'm not tracking this into your code: you didn't make it easy to read. See the PEP-8 guidelines for suggestions.
I was trying to solve problem number 12 of Project Euler. This is the problem:
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, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five
divisors.
What is the value of the first triangle number to have over five
hundred divisors?
I defined two functions to do the job:
1) allfactor(x): This gives us all the factors of a given number in a list form. Example: allfactor(10) gives us [1, 2, 5, 10]
2)TriangularNo(x): This gives us the nth Triangular number. Example TriangularNo(5) gives us 5
Here is the complete code which I wrote:
facs=[]
def allfacof(x):
for i in range(1,int(x/2)+1):
if x%i==0:
facs.append(i)
else:
pass
facs.append(x)
return(facs)
def TriangularNo(x):
no=0
for i in range(1,x+1):
no=no+i
return(no)
a=0 # a will tell us the number of iterations
while True:
a+=1
N=TriangularNo(a)
length=(len(allfacof(N)))
if int(length)>=500:
print(N)
break
else:
pass
When I run this code I get 1378 as the output which is clearly wrong because len(allfacof(1378)) turns out to be 8 and not 500 as demanded in the question.
Notice in the while loop, I use if int(length)>=500: So this means that when my code runs, length somehow gets the value = 500 but when I run the function separately it says that it's length is 8.
I am just not able to find out the error. Please help me
The problem is you are using facs as a global variable and you are only appending to the item. You should make it a member of allfacof() so that it clears out after each value.
If you look into facs then you will find it equals
1, 1, 3, 1, 2, 3, 6, 1, 2, 5, 10 ...
Although moving facs into all_factors_of() solves your immediate problem, the next problem with this code is performance. Let's consider triangle number generation first. The optimization that #Voo suggests:
def TriangularNo(n):
return n * (n + 1) / 2
is fine if we're looking for arbitrary triangle numbers -- but we're not. We're looking for sequential triangle numbers, so in this case the formula slows down our code! When going sequentially, you only need do a couple of additions to get the next triangle number -- but using the formula, you need to do an addition, a multiplication and a division! More expensive if you're going sequentially. Since we are going sequentially, this seems a perfect use of a Python generator:
def triangular_number_generator():
triangle = number = 1
while True:
yield triangle
number += 1
triangle += number
Which makes clear the two additions needed to get to the next triangle number. Now let's consider your factorization function:
Your factorization function loses performance in the way that it produces factors in order. But we're only concerned with the number of factors, order doesn't matter. So when we factor 28, we can add 1 and 28 to the factors list at the same time. Ditto 2 and 14 -- making 14 our new upper limit. Similarly 4 and 7 where 7 becomes the new upper limit. So we collect factors faster and quickly reduce the upper limit that we need to check. Here's the rest of the code:
def factors_of(number):
divisor = 1
limit = number
factors = []
while divisor <= limit:
if number % divisor == 0:
factors.append(divisor)
remainder = number // divisor
if remainder != divisor:
factors.append(remainder)
limit = remainder - 1
divisor += 1
return factors
triangular = triangular_number_generator()
number = next(triangular)
factors = factors_of(number)
while len(factors) <= 200:
number = next(triangular)
factors = factors_of(number)
print(number)
How does it compare? If we run your fixed code with a lower limit of > 200 factors, it takes about a minute to come up with the answer (2031120). The above code takes about 1/3 of a second. Now consider how long it'll take both to reach > 500 factors. Finally, to meet the stated goal:
What is the value of the first triangle number to have over five
hundred divisors?
this comparison in your original code:
if int(length)>=500:
would instead need to be:
if length > 500:
Though the way the count of factors jumps, it makes no difference for 500. But for smaller limits, for testing, it can make a difference.
The problem presented is as follows:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I have tried a few variations on the code you see below. I am currently getting the number 2,435,424 as the answer from the code I have written, however Project Euler is saying that number is incorrect. I have tried changing looking in to reasons my code is failing, and I'm stumped. Any advice would be appreciated. Code is as follows:
fibonacci = [2]
i = 0
number_1 = 1
number_2 = 2
number_3 = 0
while (number_3 <= 4000000):
number_3 = number_1 + number_2
fibonacci.append(number_3)
if i % 2 != 0:
number_1 = number_3
i += 1
elif i % 2 == 0:
number_2 = number_3
i += 1
total = 0
for numbers in fibonacci:
if numbers % 2 == 0:
total += numbers
print total
Consider the many ways you can write a Fibonacci sequence in Python.
The most 'Pythonic', IMHO, is a generator:
def fib():
a, b = 0, 1
while 1:
yield a
a, b = b, a + b
You can modify that with the limit and the test of a % 2:
def Fib_in_even(lim):
a, b = 0, 1
while a < lim:
if not a % 2:
yield a
a, b = b, a + b
Then use sum to add up the modified Fibonacci series to 'the answer':
>>> sum(Fib_in_even(4000000))
the_answer...
For one thing, your loop appends one value too many to your list. Consider what happens if number_3 equals 4 million. Your loop will then compute a new value of number_3, which will exceed 4 million because one of number_1 or number_2 will have just been set equal to number_3, and add it to your list. The same holds true for any number_3 such that number_3 <= 4000000 but number_3 + min(number_1, number_2) > 4000000, I'm just using 4 million as a value that easily demonstrates the error.
I make no comment on the general algorithm - working on that is part of the point of Project Euler. But it's worth considering what you might do if the end value were not 4 million, but something too large to keep all the Fibonacci terms in memory at once.
You're mixing doing the sum that project euler is asking for and the actual calculation of the fibonacci numbers. In the process of mixing this, you mess up both halves.
Let's do it one at a time:
fibonacci = [1, 2]
number_1 = 1
number_2 = 2
number_3 = 3
while (number_3 <= 4000000):
number_1, number_2, number_3 = number_2, number_3, number_1 + number_2
fibonacci.append(number_3)
Now, we have a list of fibonacci numbers. Let's sum the even ones.
total = 0
for numbers in fibonacci:
if numbers % 2 == 0:
total += numbers
Or more simply:
total = sum(x for x in fibonacci if x % 2 == 0)
And you'll absolutely want to apply the advice in Peter DeGlopper's answer.
You replace number_2 on the first iteration. That is not correct.
There is no need to evaluate an extra if in this case! an integer %2 is either 0 or 1, so use else.
On top of that using if/else doesn't make much sense here, you could just do a rotation instead. Try doing it by hand and you'll see.
Project Euler is more about learning to find the solution with good code and shortcuts (4 million was originally a lot and couldn't be acquired through a bad recursion that goes through both branches). So I will not include the exact solution to any Project Euler question here but point you into the right direction instead.
I highly suggest learning about python generators (see dawg's answer), since this is the easiest example to learn and understand them.
Also, it would be best to keep the running total inside your main loop so you don't have to go through them again.
Note regarding Project Euler: Python is not restricted with respect to integers (you can have infinite precision if you want) so some of the questions will not make as much sense. Also, RAM and CPU have increased exponentially; so consider doing this problem with 4 billion instead of 4 million and you will learn much more. That's where a useless elif could be expensive, and looping over something twice even worse because you have to keep track of the whole structure.
Think of it this way: can you solve the problem without keeping more than the bare-necessary variables in memory? That's where generators, xrange, etc come in very handy (python 2.x).
def FibSeries(first,second):
yield first
while True:
first,second = second,first+second
yield first
fib_lt_4mil = itertools.takewhile(lambda n:n<4000000,FibSeries(1,1))
even_fib_lt_4mil = [n for n in fib_lt_4mil if n%2 == 0]
print sum(even_fib_lt4mil)
at least I think
def EvenFibonacciNumbersSum(n):
a = 1
b = 2
temp = 0
sum =0
while(a<=n):
if(a%2 ==0):
sum = sum + a
#print(sum)
temp = a
a = b
b = temp+b
return sum
if __name__ == '__main__':
print(EvenFibonacciNumbersSum(4000000))
Background
I am stuck on this problem:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I tried to discover if the issue was my Fibonacci number generator, the code which gets the even numbers, or even the way that I add the numbers to no avail.
Code
I decided to store the numbers in lists. Here, I create them.
list_of_numbers = [] #Holds all the fibs
even_fibs = [] #Holds only even fibs
Then, I created my generator. This is a potential area of issues.
x,y = 0,1 #sets x to 0, y to 1
while x+y <= 4000000: #Gets numbers till 4 million
list_of_numbers.append(y)
x, y = y, x+y #updates the fib sequence
Then, I created some code to check if a number is even, and then add it to the even_fibs list. This is another weakpoint in the code.
coord = 0
for number in range(len(list_of_numbers)):
test_number = list_of_numbers [coord]
if (test_number % 2) == 0:
even_fibs.append(test_number)
coord+=1
Lastly, I display the information.
print "Normal: ", list_of_numbers #outputs full sequence
print "\nEven Numbers: ", even_fibs #outputs even numbers
print "\nSum of Even Numbers: ", sum(even_fibs) #outputs the sum of even numbers
Question
I know that this is a terrible way to ask a question, but what is wrong? Please don't give me the answer - just point out the problematic section.
You're stopping when the sum of the next two values in the sequence is greater than 4,000,000. You're meant to consider all values in the sequence up to 4,000,000.
I'm working on solving the Project Euler problem 25:
What is the first term in the Fibonacci sequence to contain 1000
digits?
My piece of code works for smaller digits, but when I try a 1000 digits, i get the error:
OverflowError: (34, 'Result too large')
I'm thinking it may be on how I compute the fibonacci numbers, but i've tried several different methods, yet i get the same error.
Here's my code:
'''
What is the first term in the Fibonacci sequence to contain 1000 digits
'''
def fibonacci(n):
phi = (1 + pow(5, 0.5))/2 #Golden Ratio
return int((pow(phi, n) - pow(-phi, -n))/pow(5, 0.5)) #Formula: http://bit.ly/qDumIg
n = 0
while len(str(fibonacci(n))) < 1000:
n += 1
print n
Do you know what may the cause of this problem and how i could alter my code avoid this problem?
Thanks in advance.
The problem here is that only integers in Python have unlimited length, floating point values are still calculated using normal IEEE types which has a maximum precision.
As such, since you're using an approximation, using floating point calculations, you will get that problem eventually.
Instead, try calculating the Fibonacci sequence the normal way, one number (of the sequence) at a time, until you get to 1000 digits.
ie. calculate 1, 1, 2, 3, 5, 8, 13, 21, 34, etc.
By "normal way" I mean this:
/ 1 , n < 3
Fib(n) = |
\ Fib(n-2) + Fib(n-1) , n >= 3
Note that the "obvious" approach given the above formulas is wrong for this particular problem, so I'll post the code for the wrong approach just to make sure you don't waste time on that:
def fib(n):
if n <= 3:
return 1
else:
return fib(n-2) + fib(n-1)
n = 1
while True:
f = fib(n)
if len(str(f)) >= 1000:
print("#%d: %d" % (n, f))
exit()
n += 1
On my machine, the above code starts going really slow at around the 30th fibonacci number, which is still only 6 digits long.
I modified the above recursive approach to output the number of calls to the fib function for each number, and here are some values:
#1: 1
#10: 67
#20: 8361
#30: 1028457
#40: 126491971
I can reveal that the first Fibonacci number with 1000 digits or more is the 4782th number in the sequence (unless I miscalculated), and so the number of calls to the fib function in a recursive approach will be this number:
1322674645678488041058897524122997677251644370815418243017081997189365809170617080397240798694660940801306561333081985620826547131665853835988797427277436460008943552826302292637818371178869541946923675172160637882073812751617637975578859252434733232523159781720738111111789465039097802080315208597093485915332193691618926042255999185137115272769380924184682248184802491822233335279409301171526953109189313629293841597087510083986945111011402314286581478579689377521790151499066261906574161869200410684653808796432685809284286820053164879192557959922333112075826828349513158137604336674826721837135875890203904247933489561158950800113876836884059588285713810502973052057892127879455668391150708346800909439629659013173202984026200937561704281672042219641720514989818775239313026728787980474579564685426847905299010548673623281580547481750413205269166454195584292461766536845931986460985315260676689935535552432994592033224633385680958613360375475217820675316245314150525244440638913595353267694721961
And that is just for the 4782th number. The actual value is the sum of all those values for all the fibonacci numbers from 1 up to 4782. There is no way this will ever complete.
In fact, if we would give the code 1 year of running time (simplified as 365 days), and assuming that the machine could make 10.000.000.000 calls every second, the algorithm would get as far as to the 83rd number, which is still only 18 digits long.
Actually, althought the advice given above to avoid floating-point numbers is generally good advice for Project Euler problems, in this case it is incorrect. Fibonacci numbers can be computed by the formula F_n = phi^n / sqrt(5), so that the first fibonacci number greater than a thousand digits can be computed as 10^999 < phi^n / sqrt(5). Taking the logarithm to base ten of both sides -- recall that sqrt(5) is the same as 5^(1/2) -- gives 999 < n log_10(phi) - 1/2 log_10(5), and solving for n gives (999 + 1/2 log_10(5)) / log_10(phi) < n. The left-hand side of that equation evaluates to 4781.85927, so the smallest n that gives a thousand digits is 4782.
You can use the sliding window trick to compute the terms of the Fibonacci sequence iteratively, rather than using the closed form (or doing it recursively as it's normally defined).
The Python version for finding fib(n) is as follows:
def fib(n):
a = 1
b = 1
for i in range(2, n):
b = a + b
a = b - a
return b
This works when F(1) is defined as 1, as it is in Project Euler 25.
I won't give the exact solution to the problem here, but the code above can be reworked so it keeps track of n until a sentry value (10**999) is reached.
An iterative solution such as this one has no trouble executing. I get the answer in less than a second.
def fibonacci():
current = 0
previous = 1
while True:
temp = current
current = current + previous
previous = temp
yield current
def main():
for index, element in enumerate(fibonacci()):
if len(str(element)) >= 1000:
answer = index + 1 #starts from 0
break
print(answer)
import math as m
import time
start = time.time()
fib0 = 0
fib1 = 1
n = 0
k = 0
count = 1
while k<1000 :
n = fib0 + fib1
k = int(m.log10(n))+1
fib0 = fib1
fib1 = n
count += 1
print n
print count
print time.time()-start
takes 0.005388 s on my pc. did nothing fancy just followed simple code.
Iteration will always be better. Recursion was taking to long for me as well.
Also used a math function for calculating the number of digits in a number instead of taking the number in a list and iterating through it. Saves a lot of time
Here is my very simple solution
list = [1,1,2]
for i in range(2,5000):
if len(str(list[i]+list[i-1])) == 1000:
print (i + 2)
break
else:
list.append(list[i]+list[i-1])
This is sort of a "rogue" way of doing it, but if you change the 1000 to any number except one, it gets it right.
You can use the datatype Decimal. This is a little bit slower but you will be able to have arbitrary precision.
So your code:
'''
What is the first term in the Fibonacci sequence to contain 1000 digits
'''
from Decimal import *
def fibonacci(n):
phi = (Decimal(1) + pow(Decimal(5), Decimal(0.5))) / 2 #Golden Ratio
return int((pow(phi, Decimal(n))) - pow(-phi, Decimal(-n)))/pow(Decimal(5), Decimal(0.5)))
n = 0
while len(str(fibonacci(n))) < 1000:
n += 1
print n