Simple program to find squre root using recursion - python

Hi I'm new to Python and I wrote a simple program to find the square root of a given number.
n = int(input("ENTER YOUR NUMBER: "))
g = n/2
t = 0.0001
def findRoot(x):
if ((x * x > n - t) and (x * x <= n + t)):
return x
else:
x = (x + n / x) / 2
findRoot(x)
r = findRoot(g)
print("ROOT OF {} IS {}".format(n, r))
t is the maximum error.
I know it's easy to use a while loop but I can't figure out what's wrong with this code. I debugged the code and after returning the value x (line 7), line 10 runs again resulting a "None" value.
Console output for any n, n > 0 (except 4) is ROOT OF (Given Number) IS None
Any idea how to correct the code?

You need to return something inside your else block. This should work:
def findRoot(x):
if ((x*x > n - t) and (x*x <= n + t)):
return x
else:
x = (x + n/x)/2
return findRoot(x)
An alternative as suggested by Alexander in the comment below is to remove the else altogether, because the code contained within will only ever be reached if we have not already returned inside the if block. So this is equivalent:
def findRoot(x):
if ((x*x > n - t) and (x*x <= n + t)):
return x
x = (x + n/x)/2
return findRoot(x)

Related

A Normal Distribution Calculator

so im trying to make a program to solve various normal distribution questions with pure python (no modules other than math) to 4 decimal places only for A Levels, and there is this problem that occurs in the function get_z_less_than_a_equal(0.75):. Apparently, without the assert statement in the except clause, the variables all get messed up, and change. The error, i'm catching is the recursion error. Anyways, if there is an easier and more efficient way to do things, it'd be appreciated.
import math
mean = 0
standard_dev = 1
percentage_points = {0.5000: 0.0000, 0.4000: 0.2533, 0.3000: 0.5244, 0.2000: 0.8416, 0.1000: 1.2816, 0.0500: 1.6440, 0.0250: 1.9600, 0.0100: 2.3263, 0.0050: 2.5758, 0.0010: 3.0902, 0.0005: 3.2905}
def get_z_less_than(x):
"""
P(Z < x)
"""
return round(0.5 * (1 + math.erf((x - mean)/math.sqrt(2 * standard_dev**2))), 4)
def get_z_greater_than(x):
"""
P(Z > x)
"""
return round(1 - get_z_less_than(x), 4)
def get_z_in_range(lower_bound, upper_bound):
"""
P(lower_bound < Z < upper_bound)
"""
return round(get_z_less_than(upper_bound) - get_z_less_than(lower_bound), 4)
def get_z_less_than_a_equal(x):
"""
P(Z < a) = x
acquires a, given x
"""
# first trial: brute forcing
for i in range(401):
a = i/100
p = get_z_less_than(a)
if x == p:
return a
elif p > x:
break
# second trial: using symmetry
try:
res = -get_z_less_than_a_equal(1 - x)
except:
# third trial: using estimation
assert a, "error"
prev = get_z_less_than(a-0.01)
p = get_z_less_than(a)
if abs(x - prev) > abs(x - p):
res = a
else:
res = a - 0.01
return res
def get_z_greater_than_a_equal(x):
"""
P(Z > a) = x
"""
if x in percentage_points:
return percentage_points[x]
else:
return get_z_less_than_a_equal(1-x)
print(get_z_in_range(-1.20, 1.40))
print(get_z_less_than_a_equal(0.7517))
print(get_z_greater_than_a_equal(0.1000))
print(get_z_greater_than_a_equal(0.0322))
print(get_z_less_than_a_equal(0.1075))
print(get_z_less_than_a_equal(0.75))
Since python3.8, the statistics module in the standard library has a NormalDist class, so we could use that to implement our functions "with pure python" or at least for testing:
import math
from statistics import NormalDist
normal_dist = NormalDist(mu=0, sigma=1)
for i in range(-2000, 2000):
test_val = i / 1000
assert get_z_less_than(test_val) == round(normal_dist.cdf(test_val), 4)
Doesn't throw an error, so that part probably works fine
Your get_z_less_than_a_equal seems to be the equivalent of NormalDist.inv_cdf
There are very efficient ways to compute it accurately using the inverse of the error function (see Wikipedia and Python implementation), but we don't have that in the standard library
Since you only care about the first few digits and get_z_less_than is monotonic, we can use a simple bisection method to find our solution
Newton's method would be much faster, and not too hard to implement since we know that the derivative of the cdf is just the pdf, but still probably more complex than what we need
def get_z_less_than_a_equal(x):
"""
P(Z < a) = x
acquires a, given x
"""
if x <= 0.0 or x >= 1.0:
raise ValueError("x must be >0.0 and <1.0")
min_res, max_res = -10, 10
while max_res - min_res > 1e-7:
mid = (max_res + min_res) / 2
if get_z_less_than(mid) < x:
min_res = mid
else:
max_res = mid
return round((max_res + min_res) / 2, 4)
Let's test this:
for i in range(1, 2000):
test_val = i / 2000
left_val = get_z_less_than_a_equal(test_val)
right_val = round(normal_dist.inv_cdf(test_val), 4)
assert left_val == right_val, f"{left_val} != {right_val}"
# AssertionError: -3.3201 != -3.2905
We see that we are losing some precision, that's because the error introduced by get_z_less_than (which rounds to 4 digits) gets propagated and amplified when we use it to estimate its inverse (see Wikipedia - error propagation for details)
So let's add a "digits" parameter to get_z_less_than and change our functions slightly:
def get_z_less_than(x, digits=4):
"""
P(Z < x)
"""
res = 0.5 * (1 + math.erf((x - mean) / math.sqrt(2 * standard_dev ** 2)))
return round(res, digits)
def get_z_less_than_a_equal(x, digits=4):
"""
P(Z < a) = x
acquires a, given x
"""
if x <= 0.0 or x >= 1.0:
raise ValueError("x must be >0.0 and <1.0")
min_res, max_res = -10, 10
while max_res - min_res > 10 ** -(digits * 2):
mid = (max_res + min_res) / 2
if get_z_less_than(mid, digits * 2) < x:
min_res = mid
else:
max_res = mid
return round((max_res + min_res) / 2, digits)
And now we can try the same test again and see it passes

Square Root using Babylonian Method returns wrong value

Trying to use a loop function to find the square root of a number.
I'm trying to use the Babylonian method but it will not return the correct answer. If someone could point out where I have an error that would be much appreciated.
def sqrt(number, guess, threshold):
x = number / 2
prev_x = x + 2 * threshold
while abs(prev_x - x) > threshold:
prev_x = x
x = (x + guess / x) / 2
square_root = x
return square_root
test = sqrt(81, 7, 0.01)
print (test)
Change
x = (x+guess/x)/2
as this would progress to square root of guess. Change it to
x = (x+number/x)/2
Move return statement out of the while loop
initialize x to guess instead of number/2
There's no need for a guess variable at all. Your x = number/2 is your initial guess already, and by using an arbitrarily assigned guess in your computation without updating it you certainly would not get the right number.
Replace guess with number instead, and return only when the while loop is finished, and your code would work:
def sqrt(number,guess,threshold):
x = number/2
prev_x = x+2*threshold
while abs(prev_x-x)>threshold:
prev_x = x
x = (x+number/x)/2
square_root = x
return square_root
To actually make use of guess you should keep updating it as you approximate the square root:
def sqrt(number,guess,threshold):
while abs(guess - number / guess) > threshold:
guess = (guess + number / guess) / 2
return guess

New factorial function without 0

So, the standard factorial function in python is defined as:
def factorial(x):
if x == 0:
return 1
else:
return x * factorial(x-1)
Since n! := n * (n-1) * ... * 1, we can write n! as (n+1)! / (n+1). Thus 0! = 1 and we wouldn't need that if x == 0. I tried to write that in python to but I didn't work. Can you guys help me?
Since this is a recursive function (return x * factorial(x-1)) you must have an end condition (if x == 0:).
It is true that n! == (n+1)! / (n+1) and you could change your recursive call to :
def factorial(x):
return factorial(x+1) / (x+1)
But that again would have no end condition -> endless recursion (you will calling the next (n+1)! and than the (n+2)! and so on forever (or until you'll get an exception)).
BTW, you can have the condition stop your execution at 1:
if x == 1:
return 1
You wouldn't want to use recursive function for things that are not limited, hence I suggest doing a little bit importing from the standard library
from functools import reduce
import operator
def fact(x):
if not isinstance(x, int) or x <= 0:
raise Exception("math error")
else:
return reduce(operator.mul, range(1, x + 1), 1)
print(fact("string"))
print(fact(-5))
print(fact(0))
print(fact(5))
Just realized that there is no need for a hustle like that:
def fact2(x):
if not isinstance(x, int) or x <= 0:
Exception("math error")
else:
y = 1
while x > 1:
y *= x
x -= 1
return y

Python function returning first value twice

I've written this function to calculate sin(x) using Taylor series to any specified degree of accuracy, 'N terms', my problem is the results aren't being returned as expected and I can't figure out why, any help would be appreciated.
What is am expecting is:
1 6.28318530718
2 -35.0585169332
3 46.5467323429
4 -30.1591274102
5 11.8995665347
6 -3.19507604213
7 0.624876542716
8 -0.0932457590621
9 0.0109834031461
What I am getting is:
1 None
2 6.28318530718
3 -35.0585169332
4 46.5467323429
5 -30.1591274102
6 11.8995665347
7 -3.19507604213
8 0.624876542716
9 -0.0932457590621
Thanks in advance.
def factorial(x):
if x <= 1:
return 1
else:
return x * factorial(x-1)
def sinNterms(x, N):
x = float(x)
while N >1:
result = x
for i in range(2, N):
power = ((2 * i)-1)
sign = 1
if i % 2 == 0:
sign = -1
else:
sign = 1
result = result + (((x ** power)*sign) / factorial(power))
return result
pi = 3.141592653589793
for i in range(1,10):
print i, sinNterms(2*pi, i)
I see that you are putting the return under the for which will break it out of the while loop. You should explain if this is what you mean to do. However, given the for i in range(1,10): means that you will ignore the first entry and return None when the input argument i is 1. Is this really what you wanted? Also, since you always exit after the calculation, you should not do a while N > 1 but use if N > 1 to avoid infinite recursion.
The reason why your results are off is because you are using range incorrectly. range(2, N) gives you a list of numbers from 2 to N-1. Thus range(2, 2) gives you an empty list.
You should calculate the range(2, N+1)
def sinNterms(x, N):
x = float(x)
while N >1:
result = x
for i in range(2, N):
Your comment explains that you have the lines of code in the wrong order. You should have
def sinNterms(x, N):
x = float(x)
result = x
# replace the while with an if since you do not need a loop
# Otherwise you would get an infinite recursion
if N > 1:
for i in range(2, N+1):
power = ((2 * i)-1)
sign = 1
if i % 2 == 0:
sign = -1
# The else is not needed as this is the default
# else:
# sign = 1
# use += operator for the calculation
result += (((x ** power)*sign) / factorial(power))
# Now return the value with the indentation under the if N > 1
return result
Note that in order to handle things set factorial to return a float not an int.
An alternative method that saves some calculations is
def sinNterms(x, N):
x = float(x)
lim = 1e-12
result = 0
sign = 1
# This range gives the odd numbers, saves calculation.
for i in range(1, 2*(N+1), 2):
# use += operator for the calculation
temp = ((x ** i)*sign) / factorial(i)
if fabs(temp) < lim:
break
result += temp
sign *= -1
return result

Why do these two implementations of expmod differ for large values?

I've written out a couple of functions for doing expmod, that is, (x ** y) % n. These are both standard functions, I've checked and re-checked both but can't find any silly errors.
Here's the recursive one:
def expmod(x,y,m):
if y == 0: return 1
if y % 2 == 0:
return square(expmod(x,y/2,m)) % m # def square(x): return x*x
else:
return (x * expmod(x,y-1,m)) % m
...and here's the non-recursive one:
def non_recursive_expmod(x,y,m):
x = x % m
y = y % m
result = 1
while y > 0:
if(y%2 == 1):
result = (result * x) % m
x = (x*x) % m
y = y/2
return result
They agree for small values:
>>> expmod(123,456,789) - non_recursive_expmod(123,456,789)
0
...but don't for larger ones:
>>> expmod(24354321,5735275,654) - non_recursive_expmod(24354321,5735275,654)
-396L
What's going on?
Your function non_recursive_expmod has some suspicious steps in it: Remove the %m for x and y at the beginning. Both are not needed.
Additionally make sure that the division of y is an integer division by using y = y // 2.
In total the function should look like this:
def non_recursive_expmod(x, y, m):
result = 1
while y > 0:
if y % 2 == 1:
result = (result * x) % m
x = (x * x) % m
y = y // 2
return result
Non recursive does not decrease y in case it is odd, and even part needs else in case y == 1

Categories