exercise 7.2: Think Python - python

"Encapsulate this loop in a function called square_root that takes a as a parameter, chooses a reasonable value of x, and returns an estimate of the square root of a."
def square_root(a):
x = 2
y = (x + a/x) / 2
epsilon = 0.00000000001
if abs(y - x) < epsilon:
print y
while abs(y - x) > epsilon:
x = x + 1
y = (x + a/x) / 2
break
else:
return
print y
square_root(33)
up to putting 33 for 'a', it estimates the correct square root. after that, it starts jumping exponentially, to the point where when I send 100 in for 'a', it guesses the square root to be approximately 18. I don't know if maybe this is the nature of estimating. I know of how to find the precise square root, but this is an exercise from the book "Think Python" and it's to practice with recursion and thinking algorithmically.

You shouldn't be incrementing x by 1 in the loop body. You should be setting x to y (look at the Wikipedia article and notice how x3 depends on x2, and so on):
while abs(y - x) > epsilon:
x = y
y = (x + a/x) / 2
You want to get rid of that break as well, as it makes your while loop pointless. Your final code will then be:
def square_root(a):
x = 2
y = (x + a/x) / 2
epsilon = 0.00000000001
if abs(y - x) < epsilon:
print y
while abs(y - x) > epsilon:
x = y
y = (x + a/x) / 2
print y
But there's still room for improvement. Here's how I'd write it:
def square_root(a, epsilon=0.001):
# Initial guess also coerces `a` to a float
x = a / 2.0
while True:
y = (x + a / x) / 2
if abs(y - x) < epsilon:
return y
x = y
Also, since Python's floating point type doesn't have infinite precision, you can only get about 15 digits of precision anyways, so you might as well just remove epsilon:
def square_root(a):
x = a / 2.0
while True:
y = (x + a / x) / 2
# You've reached Python's max float precision
if x == y:
return x
x = y
But this last version might not terminate if y oscillates between two values.

Here's another way; it just updates x instead of using a y.
def square_root(a):
x = a / 2.0
epsilon = 0.00000001
while abs(a - (x**2)) > epsilon:
x = (x + a/x) / 2
return x

If you want it more abstract create good-enough? and guess as primitives .. Refer to the classic text of SICP here http://mitpress.mit.edu/sicp/full-text/sicp/book/node108.html

so simple , just take x = a and then follow neuton formula , like this :
def square_root(a):
x = a
while True:
print x
y = (x+a/x)/2
if abs(y-x) < 0.0000001:
break
x = y

Related

Python function doesn't return any values

It works with certain values (e.g "100 12 2"), but fails at "102 12 2" for some reason.
Checked both on Windows and MacOS with different python versions, results are the same and are not affected by setup.
from math import floor
s, x, y = 102, 12, 2
def calc(s, x, y):
q = 0
if x > y:
while s - (s / x) > 0:
q += s / x
q1 = s / x
s = s - (s / x) * x
s += q1 * y
return floor(q)
else:
return 'Inf'
if type(calc(s, x, y)) is int:
print(calc(s, x, y))
else:
print('Inf')
Try replacing the zero in the condition with a small number, such as 1e-16:
from math import floor
s, x, y = 102, 12, 2
def calc(s, x, y):
q = 0
if x > y:
while s - (s / x) > 1e-16:
q += s / x
q1 = s / x
s = s - (s / x) * x
s += q1 * y
return floor(q)
else:
return float('Inf')
print(calc(s, x, y)) # 10
The reason of doing so is that the sequence s - s/x does not become exactly zero; it only gets arbitrarily close to zero. (Even if exact zero is guaranteed algebraically, float is subject to inherent imprecision, so you need some threshold anyways.)

Trying to create a list with variable and calculation in python in a loop to pass it to a binary search

I am trying to create a list with a variable in python within a loop so that I can calculate the value of that variable through a binary search later. This is quite similar to how an IRR is calculated. Here is what I have so far but I am unable to get it to work. Can the team help me here.
term=20
y = Symbol('y')
for i in range (1, term + 1):
eqn += (1 / ((1 + y / 2) ** (30 / 360 * term)))
data.append([eqn])
I want to use this eqn in a binary search function to evaluate the value of y:
def binary_search (100, eqn)
upperbound = 10
lowerbound = 0
y = (lower + upper) / 2
while upper < lower:
if eqn < 100:
upper = y
y = (lower + upper) / 2
elif eqn > 100:
lower = y
y = (lower + upper) / 2
print(y)
I am stuck on step 1 where I need to define a looped list with a variable itself.
from sympy import *
if __name__ == '__main__':
x = symbols('x')
gfg_exp = - 0
for i in range(1,4):
gfg_exp = gfg_exp + 1/(1 + i * x)
print("Before Integration : {}".format(gfg_exp))
# Use sympy.integrate() method
intr = solve(gfg_exp, x)
print("After Integration : {}".format(float(intr[0])))

how to find min max of three varirable using only boolean and numerical comparisons, and the abs function

i got an assignment that need to find which one is the highest, lowest, or middle
assume that value of three variable x, y, z will be randomly given and we dont know the value.
and we cant use min(), max()
can use only numerical comparisons, boolean and abs function
i spend so much times try to figure out but still stuck.
this is example one of my code but this doesn't work when y is higest number because of this line
"range_between_middle_max = abs(max_yx - max_zx) + abs(max_zx - max_zy)"
x = 23
y = 14
z = 123
range_yx = abs(x - y)
middle_yx = (x + y) / 2
max_yx = middle_yx + (range_yx / 2)
range_zx = abs(x - z)
middle_zx = (x + z) / 2
max_zx = middle_zx + (range_zx / 2)
range_zy = abs(z - y)
middle_zy = (z + y) / 2
max_zy = middle_zy + (range_zy / 2)
range_between_middle_max = abs(max_yx - max_zx) + abs(max_zx - max_zy)
middle = abs(abs(max_yx - max_zx) - max_zy)
highest = middle + range_between_middle_max
lowest = (x+y+z) - (middle + highest)
print(highest)
print(middle)
print(lowest)
We can operate comparison results as numbers to avoid using if-else:
xBz = x >= z
yBz = y >= z
xBy = x >= y
zBy = z > y
yBx = y > x
zBx = z > x
max = xBz * xBy * x + yBz * yBx * y + zBy * zBx * z
min = zBx * yBx * x + zBy * xBy * y + yBz * xBz * z

python ProjectEuler task 4 Using while loop

i wanted to do the project euler problems by using python.
but i am having problems with the following task:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 x 99.
Find the largest palindrome made from the product of two 3-digit numbers.
my code for the given task:
def palindrome_number():
n=0
lower_range = 100
upper_range = 999
while x >= lower_range or x <= upper_range and y >= lower_range or y <= upper_range:
z = x * y
while z > n:
s = str(x * y)
if s == s[::-1]:
n = x * y
print(n)
now i dont know how to check for all the x and y numbers varying from 100-999.
i thought it has to be like in my code, but it doesnt work
Solution 1: using a generator expression
Actually the problem can be solved in one line :)
max(x*y for x in range(100, 1000) for y in range(100, 1000) if str(x*y)==str(x*y)[::-1])
Solution 2: using a for loop
for loops are better suited for this kind of operation than while loops. Below is the solution (I have only replaced your while with two for loops. The first loop tells the variable x to run from 100 to 999 and the second one tells y to do the same. With these two loops you will try out all combinations for x and y.)
def palindrome_number():
n = 0
lower_range = 100
upper_range = 999
for x in range(lower_range, upper_range+1):
for y in range(lower_range, upper_range+1):
z = x * y
if z > n: # an *if* suffices ;)
s = str(x * y)
if s == s[::-1]:
n = x * y
print(n)
Solution 3: using a while loop
To get the same thing with while loops you would have to take care of changing x and y to get all combinations:
x = y = lower_range
while x >= lower_range and x <= upper_range: # (*and* instead of *or*)
while y >= lower_range and y <= upper_range: # (again you want the >= *and* the <= to be fulfilled)
z = x * y
if z > n:
s = str(x * y)
if s == s[::-1]:
n = x * y
y += 1 # change y to get all combinations
y = lower_range
x += 1 # change x to get all combinations

How to calculate a Normal Distribution percent point function in python

How do I do the equivalent of scipy.stats.norm.ppf without using Scipy. I have python's Math module has erf built in but I cannot seem to recreate the function.
PS: I cannot just use scipy because Heroku does not allow you to install it and using alternate buildpacks breaches the 300Mb maximum slug size limit.
There's not a simple way to use erf to implement norm.ppf because norm.ppf is related to the inverse of erf. Instead, here's a pure Python implementation of the code from scipy. You should find that the function ndtri returns exactly the same value as norm.ppf:
import math
s2pi = 2.50662827463100050242E0
P0 = [
-5.99633501014107895267E1,
9.80010754185999661536E1,
-5.66762857469070293439E1,
1.39312609387279679503E1,
-1.23916583867381258016E0,
]
Q0 = [
1,
1.95448858338141759834E0,
4.67627912898881538453E0,
8.63602421390890590575E1,
-2.25462687854119370527E2,
2.00260212380060660359E2,
-8.20372256168333339912E1,
1.59056225126211695515E1,
-1.18331621121330003142E0,
]
P1 = [
4.05544892305962419923E0,
3.15251094599893866154E1,
5.71628192246421288162E1,
4.40805073893200834700E1,
1.46849561928858024014E1,
2.18663306850790267539E0,
-1.40256079171354495875E-1,
-3.50424626827848203418E-2,
-8.57456785154685413611E-4,
]
Q1 = [
1,
1.57799883256466749731E1,
4.53907635128879210584E1,
4.13172038254672030440E1,
1.50425385692907503408E1,
2.50464946208309415979E0,
-1.42182922854787788574E-1,
-3.80806407691578277194E-2,
-9.33259480895457427372E-4,
]
P2 = [
3.23774891776946035970E0,
6.91522889068984211695E0,
3.93881025292474443415E0,
1.33303460815807542389E0,
2.01485389549179081538E-1,
1.23716634817820021358E-2,
3.01581553508235416007E-4,
2.65806974686737550832E-6,
6.23974539184983293730E-9,
]
Q2 = [
1,
6.02427039364742014255E0,
3.67983563856160859403E0,
1.37702099489081330271E0,
2.16236993594496635890E-1,
1.34204006088543189037E-2,
3.28014464682127739104E-4,
2.89247864745380683936E-6,
6.79019408009981274425E-9,
]
def ndtri(y0):
if y0 <= 0 or y0 >= 1:
raise ValueError("ndtri(x) needs 0 < x < 1")
negate = True
y = y0
if y > 1.0 - 0.13533528323661269189:
y = 1.0 - y
negate = False
if y > 0.13533528323661269189:
y = y - 0.5
y2 = y * y
x = y + y * (y2 * polevl(y2, P0) / polevl(y2, Q0))
x = x * s2pi
return x
x = math.sqrt(-2.0 * math.log(y))
x0 = x - math.log(x) / x
z = 1.0 / x
if x < 8.0:
x1 = z * polevl(z, P1) / polevl(z, Q1)
else:
x1 = z * polevl(z, P2) / polevl(z, Q2)
x = x0 - x1
if negate:
x = -x
return x
def polevl(x, coef):
accum = 0
for c in coef:
accum = x * accum + c
return accum
The function ppf is the inverse of y = (1+erf(x/sqrt(2))/2. So we need to solve this equation for x, given y between 0 and 1. Here is a code doing this by the bisection method. I imported SciPy function to illustrate that the result is the same.
from math import erf, sqrt
from scipy.stats import norm # only for comparison
y = 0.123
z = 2*y-1
a = 0
while erf(a) > z or erf(a+1) < z: # looking for initial bracket of size 1
if erf(a) > z:
a -= 1
else:
a += 1
b = a+1 # found a bracket, proceed to refine it
while b-a > 1e-15: # 1e-15 ought to be enough precision
c = (a+b)/2.0 # bisection method
if erf(c) > z:
b = c
else:
a = c
print sqrt(2)*(a+b)/2.0 # this is the answer
print norm.ppf(y) # SciPy for comparison
Left for you to do:
preliminary bound checks (y must be between 0 and 1)
scaling and shifting if other mean / variance are desired; the code is for standard normal distribution (mean 0, variance 1).

Categories

Resources