I am no clue of why I have the infinite loop for the codes below. Thank you for telling me and answer!
cube = 25
epision = 0.01
guess = 0
increment = 0.01
while abs(guess**3 - cube) >= epision:
guess += increment
if abs(guess**3 - cube) >= epision:
print("Failed on cube root of", cube)
else:
print (guess, 'is close to the cube root of',cube)
The problem is that even at it's closest, the absolute difference between guess**3 and cube is still 0.10291200000046885 and thus larger than epsilon.
To fix it, you could:
use a larger epsilon or smaller increment
or compare the absolute difference to the difference in the last iteration and break once it stars to rise again
or just check whether guess**3 > cube, since you are testing from 0 anyway and not doing e.g. binary search
Or, actually use binary search; it's a much better algorithm, converging much faster to the target, and for an (almost) arbitrarily small epsilon, and not that hard to implement:
lower, upper = 0, cube # cube root has to be between these two numbers
while abs(guess**3 - cube) >= epision:
if guess**3 > cube:
guess, upper = (guess + lower) / 2, guess
else:
guess, lower = (guess + upper) / 2, guess
The cube root of 25 is about 2.92402.
When guess = 2.92, guess ** 3 = 24.897, so abs(guess ** 3 - cube) == 0.103, which is not less than epsilon. So you add 0.01 to guess.
When guess = 2.93, guess ** 3 = 25.154, so abs(guess ** 3 - cube) = 0.154, which is also not less than epsilon.
As you keep adding 0.01 to guess, you'll get further away, so the loop continues infinitely.
Related
The question is
To find the square root of number āNā.using this procedure, we must implement the
following process:
Guess a value for the square root of N
Divide N by that guess
Average the result with your original guess to get your new guess
Go to step 2 and repeat
I have set the code to return the Guess once it is within 0.5 of the previous Guess, and if its not to repeat the function. I'm not sure how to make it repeat or how to close the loop.
def SqrRt(Number,Guess):
while Guess2 == ((Estimate+Guess)/2):
if (Estimate - Guess2) <= 0.5:
return Guess2
elif (Estimate - Guess2) >= -0.5:
return Guess2
else:
Estimate = (Number/Guess)
Guess2 = Estimate + 1
answer = SqrRt(34567823321421,500000)
print(answer)
Using the Babylonian Method means solving (S^2 - V) = 0. Here, S is the square root of V, which is to be found. Applying Newtons Approximation leads to an iterative method where 'x_new = (x_prev + V / x_prev) / 2'. The first 'x_prev' needs to be estimated.
The iteration converges monotonously. Thus a check against a delta in development is sufficient.
x = V / 2.0 # First estimate
prev_x = x + 2 * Delta # Some value for that 'while' holds
while abs(prev_x - x) > Delta:
prev_x = x
x = (x + V/x) / 2.0
square_root = x
Choose Delta to be arbitrarily small (e.g. 0.0001).
First off
You need code that will actually run at all for a question like this. I suggest that your code should look more like this:
def SqrRt(Number,Guess):
while Guess2 == ((Estimate+Guess)/2):
if (Estimate - Guess2) <= 0.5:
return Guess2
elif (Estimate - Guess2) >= -0.5:
return Guess2
else:
Estimate = (Number/Guess)
Guess2 = Estimate + 1
answer = SqrRt(34567823321421,500000)
print(answer)
#Number to Use - 34567823321421
#Answer - 5879440.732
I have a code that is supposed to produce the lowest monthly payment you need to make to payoff a balance within a year. It works perfectly for all numbers until (so far as I've tested) 772000000000000.
Here is the code (numbers I've tested are below with their results):
import time
balance = float(input("balance: "))
annualInterestRate = float(input("AIR: "))
# formulas for lower and higher binding for bisectional search
monthlyInterestRate = annualInterestRate / 12
lower = balance / 12
higher = (balance * (1 + monthlyInterestRate) ** 12) / 12
while True:
guess = ((higher - lower) / 2 + lower)
print('higher: %s' % higher)
print('lower: %s' % lower)
remaining = balance
for i in range(12):
unpaid = remaining - guess
remaining = unpaid + monthlyInterestRate*unpaid
if higher - lower <= .01 and remaining < 0:
result = lower
print("Lowest Payment: %s" % result)
break
elif higher - lower <= .01 and remaining >= 0:
result = higher
print("Lowest Payment: %s" % result)
break
elif remaining < -0.01:
higher = guess
print("remaining: %s" % remaining)
print(guess)
print('too high')
time.sleep(.5)
elif remaining > 0:
lower = guess
print("remaining: %s" % remaining)
print(guess)
print('too low')
time.sleep(.5)
As I said, this gives the correct result for every number I tested but then I tested 999999999999999 and I got an infinite loop, I narrowed down where the issues start happening by testing the following values all using .2 as the AIR, using different AIR can produce different but similar results depending on the number, but the following should give you a good idea of what's happening:
662000000000000 works
771999999999999 works
772000000000000 repeats higher and lower over and over again after some time
772100000000000 works
772200000000000 repeats higher and lower over and over again after some time
772300000000000 infinite loop
772400000000000 infinite loop
772500000000000 infinite loop
882100000000000 infinite loop
999999999999999 infinite loop
Feel free to try them yourself, I'm completely dumbfounded why this is happening?
If you use floats you have to consider that these cannot represent all possible decimal values. If the values get big enough the difference between two representable floating point values might just exceed your threshold. That leads to a situation where the bisection cannot progress because there is just no "middle" float between the values. For example with:
balance = float("772300000000000")
annualInterestRate = float("0.2")
It ends up in an infinite loop with:
higher: 70368815315719.6
lower: 70368815315719.58
So, let's examine this a bit:
>>> a = 70368815315719.6
>>> b = 70368815315719.58
>>> import numpy as np
>>> np.nextafter(a, 0) == np.float64(b)
True
>>> np.nextafter(b, np.inf) == np.float64(a)
True
So there's no float between a and b but:
>>> b - a
-0.015625
So this is bigger than your threshold. So nothing can change between loops which results in the infinite loop.
However, you can easily fix this by using an arbitary precision Fraction:
from fractions import Fraction
balance = Fraction("772300000000000")
annualInterestRate = Fraction("0.2")
... # rest of your code
All operations in your code preserve the Fraction (if you had used math functions or ** it could be different) and at least on my computer it eventually finishes with:
higher: 161683724083791631395206486083981108997/2297661589986627614146560
lower: 41391033365450653948925712865241263190149/588201367036576669221519360
Lowest Payment: 161683724083791631395206486083981108997/2297661589986627614146560
Note the / in the output which comes from the Fraction.
This question already has answers here:
How to find cube root using Python? [duplicate]
(3 answers)
Closed 5 years ago.
So I'm a complete beginner (like less than a week) and wrote this code in python. It's supposed to find the cuberoot of a number if the solution is an integer, and approximate it otherwise. It does both instead of just one or the other. I've tried it multiple ways for hours now but it doesn't work. Any suggestions?
cube=int(input("what number's cube root do you want to find"))
epsilon = 0.01
increment = 0.0001
num_guesses = 0
for guess in range(cube+1):
if guess**3 == cube:
guess += 1
print (guess)
else:
guess1 = 0.0
while abs(guess1**3 - cube) >= epsilon:
guess1 += increment
num_guesses += 1
print('num_guesses =', num_guesses)
else:
print(guess1)
The problem is your indentation. Everything in your "else" statement needs to be indented to show that it is inside the "else" statement. You also have a few logical errors in your code. If you have found a number that, when cubed, is the desired number, you should print that number, not that number plus 1. And if you've found the solution, your program should stop there.
for guess in range(cube+1):
if guess**3 == cube:
print (guess)
return
guess1 = 0.0
Here is the working solution:
cube=int(input("what number's cube root do you want to find: "))
epsilon = 0.01
increment = 0.0001
num_guesses = 0
int_result_found = False
for guess in range(cube+1):
if guess**3 == cube:
print guess
int_result_found = True
break
if not int_result_found:
guess1 = 0.0
while abs(guess1**3 - cube) >= epsilon:
guess1 += increment
num_guesses += 1
#print 'num_guesses =', num_guesses
print(guess1)
As Erik said, there were some errors in your code. Key point is to stop after you've found integer solution, I've used boolean flag int_result_found for that.
One of the problems with you code is indenting. Python requires specific spacing in order to work properly.
The easiest way to avoid getting both answers is to create a boolean variable (I used "found_answer") to check if it is necessary to run the second code.
I've fixed you code, modifying it as little as possible:
cube=int(input("what number's cube root do you want to find"))
found_answer = False
for guess in range(cube+1):
if guess**3 == cube:
print ("integer answer:", guess)
found_answer = True
if found_answer == False:
epsilon = 0.01
increment = 0.0001
num_guesses = 0
guess1 = 0.0
while abs(guess1**3 - cube) >= epsilon:
guess1 += increment
num_guesses += 1
print('num_guesses =', num_guesses)
print("approximate answer:", guess1)
For your interest, here is a much more efficient solver:
# target function: y = x**3
def cube(x):
return x * x * x
def diff(f, epsilon = 0.001):
"""
Given function f, return a numeric approximation function for f'(x)
"""
def df(x):
return (f(x + epsilon) - f(x)) / epsilon
return df
def newton_solver(target_y, f, df = None, start_x = None, epsilon = 0.001, max_reps = 40):
"""
Newton Raphson approximation
Given real target_y and function f,
return real x such that f(x) = target_y +/- epsilon
"""
# if no differential function is provided, use a numeric approximation
if df is None:
df = diff(f)
# if no starting point is given, guess f(x) ='= x
if start_x is None:
x = target_y
else:
x = start_x
for _ in range(max_reps):
y = f(x)
err = y - target_y
if abs(err) < epsilon:
# close enough
return x
else:
# project the tangent to find a closer approximation
x -= err / (df(x) or epsilon)
# no answer found, bail out
raise ValueError("max_reps exceeded, no solution found")
def main():
y = int(input("What integer do you want to find the cube root of? "))
# find x such that y == x**3
approx_x = newton_solver(y, cube)
# round to the nearest integer
int_x = round(approx_x)
if cube(int_x) == y:
print("The exact cube root of {} is {}.".format(y, int_x))
else:
print("The cube root of {} is approximately {}.".format(y, approx_x))
if __name__ == "__main__":
main()
when it comes to "guess**3 == cube", I think you need to "break"
try this:
cube=int(input("what number's cube root do you want to find"))
epsilon = 0.01
increment = 0.0001
for i in range(cube + 1):
if i**3 == cube:
# break the loop
break
elif (i+1)**3 > cube > i**3: # this is to reduce unnecessary calculations
while (abs(i**3 - cube) >= epsilon):
i += increment
break
print(i)
and I'd like to make it a func:
cube=int(input("what number's cube root do you want to find"))
epsilon = 0.01
increment = 0.0001
def cuberoot(cube):
for i in range(cube + 1):
if i**3 == cube:
break
elif (i+1)**3 > cube > i**3:
while (abs(i**3 - cube) >= epsilon):
i += increment
break
return i
print(cuberoot(cube))
and what is more easy:
def cuberoot(cube):
return cube**(1/3)
x = 25
epsilon = 0.01
step = 0.1
guess = 0.0
while guess <= x:
if abs(guess**2 -x) >= epsilon:
guess += step
if abs(guess**2 - x) >= epsilon:
print('failed')
else:
print('succeeded: ' + str(guess))
I am given this Python program which attempts to calculate the square root of a number x. For some reason, this program loops indefinitely and I'm not sure why.
There are only finitely many values of guess, because, after guess>x (i.e. when guess>=25.1,, the while loop then stops). The while command in the middle of the program is the only thing that loops, so what is happening?
You only increment guess when the condition abs(guess**2 -x) >= epsilon is true. That condition is false when guess = 5.0. At that point guess never changes anymore but guess <= x is still true and you enter an infinite loop:
>>> x = 25
>>> epsilon = 0.01
>>> guess = 5.0
>>> abs(guess**2 - x)
0.0
>>> abs(guess**2 - x) >= epsilon
False
Starting at guess = 0.0 and incrementing by 0.1 means that your loop executes 50 times before reaching that point, after which guess never changes again.
In reality, guess is not 5.0 exactly because adding an approximation of 0.1 (which can't be represented exactly using binary fractions), gives you a value a small amount lower:
>>> guess = 0.0
>>> for _ in range(50):
... guess += 0.1
...
>>> guess
4.999999999999998
but that difference is still smaller than epsilon.
You probably want to break the while loop when you have reached within epsilon distance of the target:
while guess <= x:
if abs(guess**2 -x) < epsilon:
break
guess += step
Even if you change the while condition to < instead of <=, it will still loop indefinitely, because of floating point inaccuracy.
Although you add steps of 0.1, the guess value will not become exactly 5, but 4.999999999999998, at which point the loop will continue to run without entering in the if block.
This is at least what I see happening here
I am trying to write a tree growing algorithm where Trees go through 2 cycles of growth every year. The first growth cycle occurs during the spring, when it doubles in height. The second growth cycle occurs during the summer, when its height increases by 1 meter.
The problem I have is that Now, a new Tree is planted at the onset of spring. Its height is 1 meter. I want to find the height of the tree after N growth cycles?
I was doing some research on recursive functions where the function is calling it self. I here it makes the code you write more elegant and simple then while loops. I am having problems execute this function though
n = input('How long would you like the tree to for?: ')
def cycle(n):
if n == 0:
n = + 1
return n
print '/n' # The reason for all the '/n' is just for neatness.
print('The tree will be ' + n + 'Ft tall')
elif n % 2 == 0:
n = 1 + cycle(n - 1)
return n
print '/n'
print('The tree will be ' + n + 'Ft tall')
elif n % 2 != 0:
n = 2 * cycle(n - 1)
return n
print '/n'
print('The tree will be ' + n + ' Ft tall')
cycle(n)
Your variable n also conflates height of the tree with the cycles of growth. You should instantiate distinct variables for distinct measurements! Also, n is being modified at all levels of the stack, likely causing the erroneous output.
Recursive calls can make algorithms more elegant, but they are also almost always less intuitive than the non-recursive solution. My recommendation to a beginning student is to solve the problem iteratively and then translate the iterative algorithm to its recursive form.
I do not believe a recursive function is the best way to go for this program. Also, for your first line, you should use int(input()), not just input(). Although, if you do wish to use recursive functions, here is my code for the program:
n = int(input("How many years does the tree grow? "))
def cycle(s, height):
height *= 2
height += 1
s -= 1
if s != 0:
cycle(s, height)
else:
print("Your tree was", height, "meters.")
cycle(n, 1)