I'm not quite sure why my recursive algorithm is not working. I get the below error but, i guess in my mind it appears i have a termination point. I know I am forgetting something simple.
RuntimeError: maximum recursion depth exceeded
def triplet(n):
a = (2*n) +1
b = (2*n)*(n+1)
c = (2*n)*(n+1) +1
if a+b+c == 1000:
return a*b*c
elif a+b+c > 1000:
return 'no triplet found'
else:
return triplet(n+1)
print triplet(1)
You are using a variant of Euclid's method for generating triples. However, it does not produce ALL possible triples, and so it clearly not generating the triples that are needed to solve your problem.
In fact, there is no universal formula for generating all Pythagorean triples. You'll need to either analytically find the solution or brute force it.
Check for greater then or equals
def triplet(n):
a = (2 * n) + 1
b = (2 * n) * (n + 1)
c = (2 * n) * (n + 1) + 1
if a + b + c >= 1000:
return a * b * c
else:
return triplet(n + 1)
print triplet(1)
Are you sure recursion/euclid's method is the best way to go about doing this one? I remember doing this by holding the sum equal to 1000, and then varying the two independent variables and checking when they were equal. (I also used some sort of the triangle inequality to decrease the number of solutions to check, but that is not necessary as at most you'll be checking 1 million possibilities).
Related
The 12th term, F12, is the first term to contain three digits.
What is the index of the first term in the Fibonacci sequence to contain 1000 digits?
a = 1
b = 1
i = 2
while(1):
c = a + b
i += 1
length = len(str(c))
if length == 1000:
print(i)
break
a = b
b = c
I got the answer(works fast enough). Just looking if there's a better way for this question
If you've answered the question, you'll find plenty of explanations on answers in the problem thread. The solution you posted is pretty much okay. You may get a slight speedup by simply checking that your c>=10^999 at every step instead of first converting it to a string.
The better method is to use the fact that when the Fibonacci numbers become large enough, the Fibonacci numbers converge to round(phi**n/(5**.5)) where phi=1.6180... is the golden ratio and round(x) rounds x to the nearest integer. Let's consider the general case of finding the first Fibonacci number with more than m digits. We are then looking for n such that round(phi**n/(5**.5)) >= 10**(m-1)
We can easily solve that by just taking the log of both sides and observe that
log(phi)*n - log(5)/2 >= m-1 and then solve for n.
If you're wondering "well how do I know that it has converged by the nth number?" Well, you can check for yourself, or you can look online.
Also, I think questions like these either belong on the Code Review SE or the Computer Science SE. Even Math Overflow might be a good place for Project Euler questions, since many are rooted in number theory.
Your solution is completely fine for #25 on project euler. However, if you really want to optimize for speed here you can try to calculate fibonacci using the identities I have written about in this blog post: https://sloperium.github.io/calculating-the-last-digits-of-large-fibonacci-numbers.html
from functools import lru_cache
#lru_cache(maxsize=None)
def fib4(n):
if n <= 1:
return n
if n % 2:
m = (n + 1) // 2
return fib4(m) ** 2 + fib4(m - 1) ** 2
else:
m = n // 2
return (2 * fib4(m - 1) + fib4(m)) * fib4(m)
def binarySearch( length):
first = 0
last = 10**5
found = False
while first <= last and not found:
midpoint = (first + last) // 2
length_string = len(str(fib4(midpoint)))
if length_string == length:
return midpoint -1
else:
if length < length_string:
last = midpoint - 1
else:
first = midpoint + 1
print(binarySearch(1000))
This code tests about 12 times faster than your solution. (it does require an initial guess about max size though)
So i'm trying to write a program which finds a Pythagorean triplet, checks if all the numbers which make up the triplet add up to 1000, and if they do then multiply the 3 numbers together and output the result. Here is my sample code:
import math
numbers = [1,2,3]
found = False
while not found:
if (math.pow(numbers[0], 2) + math.pow(numbers[1], 2)) == (math.pow(numbers[2], 2)): #Checks to see if its a pythag triplet
total = 0
for x in numbers:#adds the 3 numbers together
total += x
if total == 1000: #if the total of the three numbers is 1000, multiply them all together
product = 1
for y in numbers:
product *= y
print (product)
found = True #print the product total and end the while loop
else:
numbers = [z+1 for z in numbers] #if the total isnt 100, then just add 1 to each of the three numbers
print (numbers)
else:
numbers = [z+1 for z in numbers]#if the three numbers arent pythag triplet, then add 1 to each number
When the first triplet has been found the program seems to stop working. It dosnt seem to be able to identify any pythag triplets anymore, so I guess this is due to the "pow" function not working correctly anymore? I am new to programming so would appreciate any advice on how to overcome this and also how I could improve efficiency aswell!
Turns out, your math is incorrect.
On each iteration, every number in the triplet is increased by 1
After a iterations, in order for it to be a Pythagorean triplet, the following must hold true:
(a + 1)**2 + (a + 2)**2 == (a + 3)**2
Here 1, 2 and 3 inside the parentheses are the initial contents of the list numbers.
This simplifies to 2 * a**2 + 6 * a + 5 == a **2 + 6 * a + 9
Which is true only for a == 2
So, your code executes print (numbers) on the third (a + 1) iteration and will never terminate since a is always increasing.
Your algorithm is running an infinite loop. The condition leading to found = True is never met, so it just keeps running.
The condition to print something ((math.pow(numbers[0], 2) + math.pow(numbers[1], 2)) == (math.pow(numbers[2], 2))) just happens once, as you see printed on your screen.
You should add debug output to see what your algorithm does.
Are you sure there are integers with:
n^2 + (n+1)^2 = (n+2)^2
3*n +3 = 1000
If not, the loop won't stop. The second condition can be re-written as n = 1000/3 -1. It is not an integer, so the program is never stopping. But I suspect the first equation also have a single solution, for n=3.
Need help proving the time complexity of a recursive function.
Supposedly it's 2^n. I need to prove that this is the case.
def F(n):
if n == 0:
return 0
else:
result = 0
for i in range(n):
result += F(i)
return n*result+n`
Here's another version that does the same thing. The assignment said to use an array to store values in an attempt to reduce the time complexity so what I did was this
def F2(n,array):
if n < len(array):
answer = array[n]
elif n == 0:
answer = 0
array.append(answer)
else:
result = 0
for i in range(n):
result += F2(i,array)
answer = n*result+n
array.append(answer)
return answer
Again what I am looking for is the explanation of how to find the complexities of the two snippets of code, not interested in just knowing the answer.
All and any help greatly appreciated.
PS: for some reason, I can't get "def F2" to stay in the code block...sorry about that
Okay, the first function you wrote is an example of Exhaustive Search where you are exploring every possible branch that can be formed from a set of whole numbers up to n (which you have passed in the argument and you are using for loop for that). To explain you the time complexity I am going to consider the recursion stack as a Tree (to represent a recursive function call stack you can either use a stack or use an n-ary Tree)
Let's call you first function F1:
F1(3), now three branches will be formed for each number in the set S (set is the whole numbers up to n). I have taken n = 3, coz it will be easy for me to make the diagram for it. You can try will other larger numbers and observe the recursion call stack.
3
/| \
0 1 2 ----> the leftmost node is returns 0 coz (n==0) it's the base case
| /\
0 0 1
|
0 ----> returns 0
So here you have explored every possibility branches. If you try to write the recursive equation for the above problem then:
T(n) = 1; n is 0
= T(n-1) + T(n-2) + T(n-3) + ... + T(1); otherwise
Here,
T(n-1) = T(n-2) + T(n-3) + ... T(1).
So, T(n-1) + T(n-2) + T(n-3) + ... + T(1) = T(n-1) + T(n-1)
So, the Recursive equation becomes:
T(n) = 1; n is 0
= 2*T(n-1); otherwise
Now you can easily solve this recurrence relation (or use can use Masters theorem for the fast solution). You will get the time complexity as O(2^n).
Solving the recurrence relation:
T(n) = 2T(n-1)
= 2(2T(n-1-1) = 4T(n-2)
= 4(2T(n-3)
= 8T(n-3)
= 2^k T(n-k), for some integer `k` ----> equation 1
Now we are given the base case where n is 0, so let,
n-k = 0 , i.e. k = n;
Put k = n in equation 1,
T(n) = 2^n * T(n-n)
= 2^n * T(0)
= 2^n * 1; // as T(0) is 1
= 2^n
So, T.C = O(2^n)
So this is how you can get the time complexity for your first function. Next, if you observe the recursion Tree formed above (each node in the tree is a subproblem of the main problem), you will see that the nodes are repeating (i.e. the subproblems are repeating). So you have used a memory in your second function F2 to store the already computed value and whenever the sub-problems are occurring again (i.e. repeating subproblems) you are using the pre-computed value (this saves time for computing the sub-problems again and again). The approach is also known as Dynamic Programming.
Let's now see the second function, here you are returning answer. But, if you see your function you are building an array named as array in your program. The main time complexity goes there. Calculating its time complexity is simple because there is always just one level of recursion involved (or casually you can say no recursion involved) as every number i which is in range of number n is always going to be less than the number n, So the first if condition gets executed and control returns from there in F2. So each call can't go deeper than 2 level in the call stack.
So,
Time complexity of second function = time taken to build the array;
= 1 comparisions + 1 comparisions + 2 comparisions + ... + (n-1) comparisions
= 1 + 2 + 3 + ... + n-1
= O(n^2).
Let me give you a simple way to observe such recursions more deeply. You can print the recursion stack on the console and observe how the function calls are being made. Below I have written your code where I am printing the function calls.
Code:
def indent(n):
for i in xrange(n):
print ' '*i,
# second argument rec_cnt is just taken to print the indented function properly
def F(n, rec_cnt):
indent(rec_cnt)
print 'F(' + str(n) + ')'
if n == 0:
return 0
else:
result = 0
for i in range(n):
result += F(i, rec_cnt+1)
return n*result+n
# third argument is just taken to print the indented function properly
def F2(n, array, rec_cnt):
indent(rec_cnt)
print 'F2(' + str(n) + ')'
if n < len(array):
answer = array[n]
elif n == 0:
answer = 0
array.append(answer)
else:
result = 0
for i in range(n):
result += F2(i, array, rec_cnt+1)
answer = n*result+n
array.append(answer)
return answer
print F(4, 1)
lis = []
print F2(4, lis, 1)
Now observe the output:
F(4)
F(0)
F(1)
F(0)
F(2)
F(0)
F(1)
F(0)
F(3)
F(0)
F(1)
F(0)
F(2)
F(0)
F(1)
F(0)
96
F2(4)
F2(0)
F2(1)
F2(0)
F2(2)
F2(0)
F2(1)
F2(3)
F2(0)
F2(1)
F2(2)
96
In the first function call stack i.e. F1, you see that each call is explored up to 0, i.e. we are exploring each possible branch up to 0 (the base case), so, we call it Exhaustive Search.
In the second function call stack, you can see that the function calls are getting only two levels deep, i.e. they are using the pre-computed value to solve the repeated subproblems. Thus, it's time complexity is lesser than F1.
I'm super new to programming and just wanted to make something to find the approximate value of x for the equation x^3 - 1 = x. I know that -2 is greater than 0 and -1 is less. My thought is that if I find the average and check if it's greater or less than 0, I can redefine a and b and repeat until I get an approximate value. I've been having a hard time getting it to act right though. For example if I run this block without the print(i), I'll get -1.5 which would be the average, but when I put a print(total) within the function equation(n) to see if it's working right, it doesn't even show me that and just outputs -8.881784197001252e-16. If I put print(i) at the end of the if/else possibilities, such as this, it prints 16 and then -8.881784197001252e-16. I'm using PyCharm CE.
Beyond this glitch, is my logic correct? By setting the placeholder to 1 it will run the while loop. The while loop will get a new value of n and run the function, compare it to 0, then reassign a or b depending on that comparison? Thanks in advance.
a = float(-2)
b = float(-1)
n = ((a+b)/2)
print(n)
def equation(n):
total = float((n - n**3 - 1))
return total
i = 1
while i != 0:
n = ((a + b) / 2)
if (equation(n)) > 0.0:
a = n
i = equation(n)
print(i)
else:
b = n
i = equation(n)
print(i)
Moving all of the equation x^3 - 1 = x to one side should give x^3 - 1 - x = 0 or x - x^3 + 1 = 0. You have a different equation in your function.
Another problem is that there is no intersection between the two equations between x=-2 and x=-1 (see here). You'll need to expand your window to x=2 before you'll see an intersection.
Something that often happens in numerical analysis (where you'll see this type of problem) is that rather than trying to find x that actually makes the equation give 0, we look for a value of x that produces below an acceptable level of error. Another approach is to test for while b - a > tol:
If we use all of this to tweak what you've got, you'll have
a = float(-2)
b = float(2)
tol = 0.001
def equation(n):
return float(n - n**3 + 1)
n = (a + b) / 2
iter = 0
while abs(equation(n) - 0) > tol and iter < 100:
iter+=1
if equation(n) > 0.0:
a = n
else:
b = n
n = (a + b) / 2
print(iter,a,b,equation(n))
Note: this works fine if you remove the floats and just do
a = -2
b = 2
#...etc
because python already recasts values as necessary. Try
>>> type(3)
<class 'int'>
>>> type(3.5)
<class 'float'>
>>> type(float(3))
<class 'float'>
>>> type(3/5)
<class 'float'>
so python will store the result as a float as soon as it is necessary.
The immediate problem is the limited precision of floats. If you print a and b after a hundred iterations, you get:
a, b = -1.324717957244746, -1.3247179572447458
print((a + b) / 2 # -1.3247179572447458, the same as b
So at some point, b never changes, which is why you get an infinite loop. If we evaluate equation at the average of a and b, you'll get -8.881784197001252e-16, the value you were always seeing.
But this will never converge to exactly zero because the solution is irrational, so even if you had infinite precision, equation would never equal zero.
The common way to resolve this issue is to avoid comparing floats:
if a == b # don't do this
if abs(a - b) < epsilon # do this, where epsilon is some small value
(Note: what you're describing is the bisection method, which is slower than higher order algorithms e.g. Newton's method, which you can use since you can get the derivative)
I'm trying to model this problem (for details on it, http://www.mpi-hd.mpg.de/personalhomes/bauke/LABS/index.php)
I've seen that the proven minimum for a sequence of 10 digits is 13. However, my application seems to be getting 12 quite frequently. This implies some kind of error in my program. Is there an obvious error in the way I've modeled those summations in this code?
def evaluate(self):
self.fitness = 10000000000 #horrible practice, I know..
h = 0
for g in range(1, len(self.chromosome) - 1):
c = self.evaluateHelper(g)
h += c**2
self.fitness = h
def evaluateHelper(self, g):
"""
Helper for evaluate function. The c sub g function.
"""
totalSum = 0
for i in range(len(self.chromosome) - g - 1):
product = self.chromosome[i] * self.chromosome[(i + g) % (len(self.chromosome))]
totalSum += product
return totalSum
I can't spot any obvious bug offhand, but you're making things really complicated, so maybe a bug's lurking and hiding somewhere. What about
def evaluateHelper(self, g):
return sum(a*b for a, b in zip(self.chromosome, self.chomosome[g:]))
this should return the same values you're computing in that subtle loop (where I think the % len... part is provably redundant). Similarly, the evaluate method seems ripe for a similar 1-liner. But, anyway...
There's a potential off-by-one issue: the formulas in the article you point to are summing for g from 1 to N-1 included -- you're using range(1, len(...)-1), whereby N-1 is excluded. Could that be the root of the problem you observe?
Your bug was here:
for i in range(len(self.chromosome) - g - 1):
The maximum value for i will be len(self.chromosome) - g - 2, because range is exclusive. Thus, you don't consider the last pair. It's basically the same as your other bug, just in a different place.