About MIT 6.00 course lec06--Newton's method - python

I have tried to code in my own way, but found I got the wrong answer.
I have read this page. And try to start the process:
f(x)=x^2-e
The math:
So there is my code:
def sqrtRootNR(num, count, epsl):
"""
for test
"""
num = float(num)
guess = num / 2.0
diff = guess ** 2.0 - num
_cnt = 0
while abs(diff) > epsl and _cnt < count:
guess = guess - (guess ** 2.0 + epsl) / (guess * 2.0)
diff = guess ** 2.0 - num
_cnt = _cnt +1
print guess, _cnt
sqrtRootNR(2, 100, 0.0001)
However, I got the wrong answer.
The output of this function is:
D:\poc>python sq.py
0.0595177826557 100

One important skill in programming is knowing which information where will be most useful. If you add some simple debugging information:
while abs(diff) > epsl and _cnt < count:
guess = guess - (guess ** 2.0 + epsl) / (guess * 2.0)
diff = guess ** 2.0 - num
print guess, _cnt
_cnt = _cnt +1
print guess, _cnt
You can see that your program goes wrong quickly:
$ ./sqrt.py
0.49995 0
0.249874989999 1
0.124737394941 2
0.0619678553654 3
0.0301770577385 4
0.0134316410297 5
0.00299326718803 6
-0.0152075217183 7
-0.00431591416548 8
0.00942707405618 9
-0.000590335594744 10
....
It appears to halve the number every iteration until it goes negative, when the behavior gets very difficult to tell just at a glance. But you can obviously tell that the very first few iterations are wrong.
Something that looks quite fishy to me: (guess ** 2.0 + epsl)
You shouldn't actually use epsilon when evaluating Newton's method for square roots -- after all, you're trying to make sure your error is less than epsilon.

It looks like you are looking for zeroes of the function f = x^2+eps1. If eps1 is positive, there will be no real zeroes. This means that your program will oscillate around 0 forever after a certain point, as you saw. If you set eps1 to a negative value, I expect you would find a root.
Newton's method isn't bullet-proof, and there are cases where it can diverge.

Change (guess ** 2.0 + epsl) to (guess ** 2 - num) in your equation. You want to adjust your estimate every step by an amount proportional to your error, ie. your diff variable.

You also can use guess = 0.5 * (guess + num/guess)

Related

Infinite loop when trying to find cube root of a non-perfect cube through bisection search

This code gives pretty accurate result when deltanum = 0.0000000000001 but gets into an infinite loop when deltanum = 0.00000000000001(adding another zero into deltanum).
It occurs only for non-perfect cubes, it works fine for perfect cubes like 1000. Why?
I am new to programming, following OSSU.
num = 100
high = num
low = 0
icount = 0
cuberoot = (high + low)/2 #cuberoot of num
deltanum = 0.00000000000001
while abs(cuberoot**3 - num)>=deltanum:
icount+=1
print(icount)
if cuberoot**3 > num:
high = cuberoot
elif cuberoot**3 < num:
low = cuberoot
else:
break
cuberoot = (high + low)/2
print("Cube root: " + str(cuberoot))
print("Number of iterations: " + str(icount))
You are using floats. float math is flawed precision wise - your delta might be to small to work correctly and your solution flipps between values without ever reaching your while conditions limit. See Is floating point math broken? for more reasoning about why float is sometimes "broken".
You can limit it to a certain amount of repeats as well:
num = 100
high = num
low = 0
icount = 0
maxcount = 100000
cuberoot = (high + low)/2 #cuberoot of num
deltanum = 0.00000000000001
while abs(cuberoot**3 - num)>=deltanum:
icount+=1
print(icount)
if cuberoot**3 > num:
high = cuberoot
elif cuberoot**3 < num:
low = cuberoot
else:
break
cuberoot = (high + low)/2
if icount > maxcount:
print("Unstable solution reached after ",maxcount, "tries")
break
print("Cube root: " + str(cuberoot) + " yields " + str(cuberoot**3))
print("Number of iterations: " + str(icount))
Output:
Unstable solution reached after 100000 tries
Cube root: 4.641588833612779 yields 100.00000000000003
Number of iterations: 100001
Most people would name that epsilon, and would use delta for cuberoot**3 - num.
Toward the end, you're hoping that this expression,
cuberoot = (high + low)/2
will buy you approximately one more bit of precision in your answer on each iteration.
(Near the beginning it approximately cuts the number of error bits in half each time.)
You're complaining that an IEEE-754 double has limited precision when computing cubes, and also differences.
Fifty-three bits gives you almost sixteen decimal digits, and your epsilon is 1e-14.
But an input num that is a few digits long will eat away at your margin, as you found.
For higher precision computations, you might prefer to use Decimal.
Or, look into the gmp library.
You believe a certain loop invariant holds,
that the quanities cuberoot and cuberoot ** 3 will change on each iteration.
It's simple to verify.
Just assign them to temp variables, and verify they change.
Terminate the loop early if they don't.
More generally, to detect oscillation between a handful of limiting values, put previous values in a set and terminate early upon seeing a repeat value.

What makes this code so slow? (for project Euler q45)

I just solved and found the answer for problem 45 on project euler, however the solution took twenty minutes to compute. Other similar solutions take less than a second to find the solution.
The problem
My code:
import time
def is_triangular(n):
triangle_index = (((8 * n + 1) ** 0.5) + 1) / 2
if triangle_index % 1 == 0:
return True
return False
def is_pentagonal(n):
pentagonal_index = (((24 * n + 1) ** 0.5) + 1) / 6
if pentagonal_index % 1 == 0:
return True
return False
def is_hexagonal(n):
hexagonal_index = (((8 * n + 1) ** 0.5) + 1) / 4
if hexagonal_index % 1 == 0:
return True
return False
number = 40756
while True:
if is_triangular(number) and is_pentagonal(number) and is_hexagonal(number):
print(number)
break
number += 1
Instead of going through every number and checking if its triangular, pentagonal and hexagonal. Generate Hexagonal numbers and for each hexagonal number check if its triangular or pentagonal.
You can generate hexagonal numbers by using the formula for hexagonal numbers and increasing n by 1.
Because you are looking to every natural number after 40755. Limit the case to a subset of real numbers: if you know already that a number is not hexagonal you can discard it already, for example.
Since the hexagonals are in the less dense subset, start by looking to numbers in that set. Then, check if they're pentagonals, and eventually check if those are triangular too.
main function example:
hex = 144
while True:
number = hex*(2*hex-1)
if is_hexagonal(number):
if is_pentagonal(number):
if is_triangular(number):
print("Found: {}".format(number))
break
hex += 1
There are other modifications that can be done in the Python code, but I focused on the algorithm only.

Python: Closest Power of Two To Target

I am attempting to find the closest power of two that is greater than or equal to a target value. A for loop must be used to achieve this. However, I am unsure of what to put as the range value so that upon reaching the required value the exponent will stop increasing by i and instead exit the for loop. Thanks for your help.
target = int(input("Enter target number: "))
def power_of_two(target):
x = 2
change = 0
power = 0
for i in range():
number = x ** change
change = i
if number >= target:
power = number
return power
p = power_of_two(target)
print("The closest power of 2 >= {0:d} is {1:d}." .format(target, p))
since you have to use for:
def power_of_two(target):
if target > 1:
for i in range(1, int(target)):
if (2 ** i >= target):
return 2 ** i
else:
return 1
that is assuming you want the value to be greater than or equal to 2^0
I have corrected your code, so that it works. I think you learn best from your mistakes :)
target = int(input("Enter target number: "))
def power_of_two(target):
x = 2
change = 0
power = 0
for i in range(target+1):
# target is okay for this, function terminates anyway
# add one to avoid error if target=0
number = x ** change
change = i
if number >= target: # you had indentation errors here and following
power = number
return power
p = power_of_two(target)
print("The closest power of 2 >= {0:d} is {1:d}." .format(target, p))
You could find a perfect value for the end of the range using logarithm with base 2, but then you wouldn't need the for loop anyway ;)
As a suggestion: maybe take a look at the binary representation of powers of 2. You could use a for loop with bitshifting for this.
EDIT: I had indentation errors myself, because of the weird formatting system here... maybe you haven't had these before :D

Logical thinking for a Calculation of Square root

I've been trying to decipher this problem for the last hour right now and having some trouble here. This is the problem
This method for calculating the square root of a number n starts by
making a (non zero) guess at the square root. It then uses the
original guess to calculate a new guess, according to the formula
newGuess = ((n / oldGuess) + oldGuess) / 2.0;
Have two variables oldGuess and newGuess. Initialize oldGuess to
n / 2.0 and calculate newGuess according to the above formula. Use
a while loop to iterate as long as the absolute value of the
difference between the oldGuess and newGuess is greater than
1.0E-06. Do not forget to reset the value of oldGuess to the
newGuess value in the while loop.
In your program you will prompt the user to enter a positive number.
If the number is negative, print an error message and ask the user to
try again. For a positive number, calculate the square root using the
above method. Find the difference between the square root you obtained
and the value obtained from using the exponentiation operator. Write
out the value the user entered, the square root you computed, and the
difference (your square root - n ** 0.5)
This is my program so far
def main():
n = eval(input("Enter a positive number: "))
while (n <= 0):
print ("Error please re-input")
n = eval(input("Enter a positive number: "))
oldGuess = n / 2.0
newGuess = ((n / oldGuess) + oldGuess) / 2.0;
difference = n - n ** 0.5
while (difference < 1 * 10 ** -6):
print ("Error")
difference = abs(n - n ** 0.5)
print ("Difference:", difference)
main()
So I don't really understand how we can tell the program to make a guess and then calculate the square root of variable n. I don't even think my while statements are right in this context. I don't use the already embedded function the squareroot built into python so it has to be done manually I believe still lost on what it means by the guess function.
while True:
n = float(input("Enter a positive number: "))
if n > 0:
break
print ("Error please re-input")
oldGuess = n / 2.0
while True:
newGuess = ((n / oldGuess) + oldGuess) / 2.0;
oldGuess = newGuess
if -1e-6 < n - newGuess * newGuess < 1e-6:
break
print ("Difference:", abs(n ** .5 - newGuess))
Change those eval()s to float()s. eval() executes any code it's handed, so that means your user could type something malicious there.
Now, use this for the second part:
oldGuess = n / 2.0
newGuess = ((n / oldGuess) + oldGuess) / 2.0
while (abs(oldGuess - newGuess) > 1e-06):
oldGuess, newGuess = newGuess, ((n / oldGuess) + oldGuess) / 2.0
print("Guess: " + str(n))
print("My root: " + str(newGuess))
print("Accuracy: " + str(newGuess - (n**0.5)))
That comma syntax is a Python idiom useful for swapping values without having to do:
temp = new
new = old * something
old = temp
Your condition for the while loop is looking to end looping when your difference is less than that (very small) value. So you will loop so long as it is greater than that.
Note: you can also use math.sqrt(n) instead of n ** 0.5. You'll have to import math.
If you want to see what your program is doing, try printing the values of oldGuess and newGuess within the while loop. You'll see it's changing them until you've arrived at your answer.
Edit:
I notice that you seem to be tripped up on why you have to do oldGuess = newGuess. Let me explain: the = operator is not the same as the equals sign in mathematics. The equals sign says that the thing on the left is the same thing as the thing on the right; i.e. they are equivalent. In Python, the = operator says "give the thing on the left the same value as the thing on the right." It is called the assignment operator. You are thinking of the == operator, which tests for equivalency (basically).
>>> a = 10
>>> b = 4
>>> b = a
>>> b
10
>>> a == b
True
>>> c = 6
>>> b = c
>>> b
6
>>> a == b
False
>>> b == c
True
>>> a == c
False
>>> a,b,c
(10, 6, 6)
As you can see, when you use the = operator, you don't "link" the variables together, saying that they are now the same thing. If you set b = a and then set b = c, b == a becomes false because b does not have the same value as a anymore. a does not change either, because b was assigned its value, not the other way around. Think of the = operator looking like <- instead (I think some languages actually use this as the assignment operator).
Why does this matter? Well, you do assign something new to a variable, you forget the old value. Unless you have another variable storing the same value, it's lost forever. Your assignment says to update the oldGuess to the previous newGuess. In other words, if your guesses were "a", "b", "c", "d", then you'd start with oldGuess as "a" and from there compute newGuess as "b". Since this would obviously not be the correct guess, you say the oldGuess is now what the newGuess just was - "b", and you compute the next newGuess, which is "c".
You need the value of oldGuess to compute the value of newGuess. But, you need the value of newGuess (before you changed it) to update the value of oldGuess. It's a catch-22, unless you store the previous value of newGuess as I showed above (as the swapping example). That is why you need this.
So I figured it out thanks guys for help. I didn't know we can't post homework questions on here but I am trying to definitely learn how to code so I can get better at it. Here was my final solution.
def main():
n = float(input("Enter a positive number: "))
while (n <= 0):
print ("Error please re-input")
n = eval(input("Enter a positive number: "))
oldGuess = n / 2.0
newGuess = 0
difference = 10
while (difference >= 1 * 10 ** -6):
newGuess = ((n / oldGuess) + oldGuess) / 2.0
difference = abs(newGuess - oldGuess)
oldGuess = newGuess
print ("Square Root is: ", newGuess)
differenceSqrt = newGuess - n ** 0.5
print ("Difference is: ", differenceSqrt)
main()
I still don't know how to use breaks effectively so thanks gnibbler but couldn't really follow your code too well. (New to this, sorry)

Why does recursive sequence not work correctly?

I'm totally new to Python and I'm trying to print the solution for a recursive sequence:
#Input sequence variables
a = float(raw_input("type in a = "))
n0 = int(raw_input("type in n_0 = "))
n1 = int(raw_input("type in n_1 = "))
y0 = float(raw_input("type in y_0 = "))
#Define function y_n (forward iteration)
def yn(n):
if (n==0):
return y0
else:
return (1/n)-a*yn(n-1)
#backward iteration
def yn_back(n):
return (1/a)*((1/n)-yn(n-1))
if(n1>=n0):
for i in range(n0,n1+1):
print(yn(i))
else:
for i in range(n0,n1+1):
print(yn_back(i))
But if I run this script with a=5, n0=1, n1=30 and y0=log(5/6)=0.182322 the solutions are very high (from 0.08839 to 3.29e+18) and the values are negative for even n. The solution is right for n=1. For other n, the (1/n) in the definition of yn(n) seems to be ignored.
Can someone help me?
Thanks a lot!
n is probably an integer, so 1/n is returning 0 for n greater than 1:
>>> 1/1
1
>>> 1/2
0
>>> 1.0/2
0.5
To make sure you're using float division, change 1 to 1.0 wherever you calculate 1/n:
(1.0/n)
Or convert n into a float.

Categories

Resources