Looking for pi until percent error is below 1e-2 - python

I'm using this formula that involves factorials and double factorials to find value of pi until percent error is below 1e-2. For some reason the while loop that's calculating pi until that PE is low enough doesn't stop (at least that's what I think is happening).
import numpy as np
k = 1
pe = 100
def doublefactorial(n):
if n == 0 or n == 1:
return 1
return n * doublefactorial(n - 2)
while pe >= 1e-2:
f = 1
for i in range(1, k + 1):
f = f * i
D = doublefactorial(2 * k + 1)
r = f / D
pe = abs(((r - np.pi) / np.pi) * 100)
k = k + 1
print("pi= ", r, "PE= ", pe)

There were a couple of things that could be improved in your code, below is a commented version with said improvements:
That for you are using to calculate k! was hard to understand, so I used python's factorial function and changed your f/D to N/D, keeping the fraction form you used.
This is a summation, so don't forget to update r's value every iteration.
The output of the formula is Pi / 2, so you can't compare it directly with np.pi.
You start with k=1, but your formula states k=0.
Also I moved the print inside the loop so you can see the values updating on each iteration.
import numpy as np
import math
k = 0
r = 0
pe = 100
def doublefactorial(n):
if n == 0 or n == 1:
return 1
return n * doublefactorial(n - 2)
while pe >= 1e-2:
# using math.factorial for easier to read code
N = math.factorial(k)
D = doublefactorial(2 * k + 1)
# our approximation = numerator / dividend
# update r's value (this is equivalent to r = r + N/D)
r += N / D
# don't forget the formula gives Pi/2 so to compare and print we should double it...
pi_approx = 2 * r
pe = abs(((pi_approx - np.pi) / np.pi) * 100)
k = k + 1
print("pi= ", pi_approx, "PE= ", pe)

Related

How to calculate coefficients, solutions etc. in quadratic function with limited inputs in Python

I have a problem. I want to calculate everything in the quadratic function. equations for reference:
ax^2 + bx + c
a(x-p)^2 + q
I made 8 possible inputs in tkinter and I want my program to try and calculate everything if possible. Otherwise to return sth like not enough data.
Equations:
delta = b^2-4ac
p = -b/(2a)
p = (x1+x2)/2
q = -delta/(4a)
#if delta>0
x2 = (-b-sqrt(delta))/(2a)
x1 = (-b+sqrt(delta))/(2a)
#if delta=0
x0 = -b/(2a)
#if delta<0 no solutions
#a, b, c are the coefficients.
b = -2ap
c = p^2*a+q
Example:
Input:
p = 3
q = -9
x1 = 0.877868
a = 2
Output:
b = -12
c = 9
x2 = 5.12132
delta = 72
So, for example, I give it [x1, x2, a] and it will calculate [q, p, b, c, and delta] if possible.
Is there a function that I can give all different formulas to and it will try to calculate everything?
For now, my only idea is to brute force it in 'try' or with 'ifs', but I feel like it would take thousands of lines of code, so I won't do that.
I found out that you can use sympy's solve. This is my solution. I used Eq for defining equations and then solved them.
def missingVariables(dictOfVariables):
symbols = dict(a=sym('a'), b=sym('b'), c=sym('c'), p=sym('p'), q=sym('q'), x1=sym('x1'), x2=sym('x2'),
delta=sym('delta'))
var = mergeDicts(symbols, dictOfVariables)
deltaEQ = Eq((var['b'] ** 2 - 4 * var['a'] * var['c']), var['delta'])
x1EQ = Eq(((-var['b'] - sqrt(var['delta'])) / (2 * var['a'])), var['x1'])
x2EQ = Eq(((-var['b'] + sqrt(var['delta'])) / (2 * var['a'])), var['x2'])
pEQ = Eq((-var['b']) / (2 * var['a']), var['p'])
pEQ2 = Eq(((var['x1'] + var['x2']) / 2), var['p'])
qEQ = Eq(((-var['delta']) / (4 * var['a'])), var['q'])
bEQ = Eq((-2 * var['a'] * var['p']), var['b'])
cEQ = Eq((var['a'] * var['p'] ** 2 + var['q']), var['c'])
solution = solve((deltaEQ, x1EQ, x2EQ, pEQ, pEQ2, qEQ, bEQ, cEQ))
solution = solution[0]
new_dict = {}
for k, v in solution.items():
try:
new_dict[str(k)] = round(float(v), 4)
except TypeError:
new_dict[str(k)] = v
return new_dict

Price approximation of European call option using the explicit finite difference method in python not working

I'm trying to approximate the European call option price of the Black-Scholes model (PDE) by the explicit finite difference method in python. For reference, the exact solution using the Black-Scholes formula is 10.247013813310648
Here is a link about the PDE Black-Scholes Equation and the discretized version of the equation can be found here Explicit finite difference method for Black-Scholes model
Can anyone point out why I'm not getting an approximation?
import numpy as np
# Terminal time
T = 0.25
# Strike price
K = 10
# risk free rate
r = 0.1
# volatility (systemic/market risk)
sigma = 0.4
# initial asset value
S0 = 20
# Assume an upper limit for the underlying stock that is 3 - 4 times the exercise price
S_max = 3 * K
# Number of space intervals
M = 200
# space mesh and space step
space_mesh, space_step = np.linspace(0, S_max, M, retstep=True)
# Stability condition
stability_cond = 1 / ( sigma**2 * (M-1) + 0.5* r )
# Find the number of time intervals and time steps that satisfy the stability condition
for percentage in np.arange(.99, .0001, -.0001):
time_step = np.round(percentage * stability_cond, 6)
N = T / time_step
if N.is_integer():
print("Number of time intervals = ", N," ", "time step = ", time_step)
# Choose number of time intervals
N = 2000
# time mesh
time_mesh, time_step = np.linspace(0, T, N, retstep= True)
# time step
time_step = np.round(time_step, 6)
# unknown u at new time level
u = np.zeros(M)
# u at the previous time level
u_prev = np.zeros(M)
# initial condition
for m in range(0, M):
u_prev[m] = np.maximum(space_mesh[m] - K, 0)
# Explicit finite difference scheme
for n in range(0, N):
for m in range(1,M-1):
a = 0.5 * time_step * ( sigma**2 *m**2 - r * m )
b = 1 - time_step * ( sigma**2 * m**2 + r )
c = 0.5 * time_step * ( sigma**2 * m**2 + r * m)
# The discretized version of the Black-Scoles PDE
u[m] = a * u_prev[m-1] + b* u_prev[m] + c * u_prev[m+1]
# insert boundry conditions
u[0] = 0
u[M-1] = S_max
# update u_prev before next iteration
u_prev[:] = u

Why do I get the message "TypeError: 'complex' object is not subscriptable" when trying to use a complex number in a np.sum?

Am trying to write code for an equation that includes complex number, and put it into a function for simpsons rule.
import numpy as np
import cmath as cmp
import matplotlib.pyplot as plt
wavelength = 0.000001 #meters
Apw = 0.00002 # meters Apw taken as apeture width
z = 0.02 # meters
N = 100
permittivity = 0.00000000000885418783
c = 299792458 # m/s
k = (2*cmp.pi)/wavelength
j = 0 + 1j
n = 100
x = np.linspace(-0.005, 0.005, n, 1.1)
def simps (N, k, Apw, x):
S = 0
h = Apw / N
for i in range(0, N + 1):
for xprime in range(0, N+1):
xprime = Apw*xprime/N
f = cmp.exp(((j*k)/(2*z))*(x-xprime)**2)
if (i != 0) and (i != n):
f *= (2 + (2 * (i % 2)))
S = h/3 * np.sum(f[0:-1:2] + 4*f[1::2] + f[2::2])
return S
x = np.linspace(-0.005, 0.005, n, 1.1)
I = np.zeros([n])
for i in range(0,n):
E_0 = simps(N, k, Apw, x[i])[0]
I[i] = permittivity*c*(E_0 * cmp.conj(E_0)).real
Where j is a complex number j = 0 + 1j
I don't really know if what I am doing is anywhere near correct, the lines that are causing the error is line 46 and 36
In your code, f is a complex number. As the error message says, you can subscript (use square braces on) a complex number. For this reason, the expressions f[0:-1:2], f[1::2] and f[2::2] are illegal operations that are producing this error. It seems that maybe you think that f is a list of complex values, rather than a single value?
If you do know that f is a single complex value, then the only operations on it that I can think of are to extract the real and imaginary parts with f.real and f.imag.

binom.pmf only returning zero

code:
def expected_profit(n):
total = 0
X = np.arange(0,n+1)
p = np.arange(0,n+1)
profit = np.arange(0,n+1)
for i in list(range(1,n+1)):
print("X_i:", X[i])
p[i] = binom.pmf(X[i],n,19/20)
print(p[i])
if X[i] > 100:
profit[i] = 50*n-60*(X[i]-100)
else:
profit[i] = 50*n
total += profit[i]*p[i]
return total
expected_profit(10)
>>>0
For some reason, after each iteration, p[i] is equal to zero. Yet when I manually type out (for example) binom.pmf(10,10,19/20) I get a non zero answer. What is the problem here?
This seems to happen with any call to binom.pmf within the function call.
With p = np.arange(0,n+1) you initialize p with an integer array 0,...,n. That makes that binom.pmf(...) is converted to an integer when assigned to p[i]. The solution is to make p an array of floats. np.zeros() by default creates an array of floats. The same problem holds for profit.
Fitting this into the code would look like:
from scipy.stats import binom
import numpy as np
def expected_profit(n):
n = 10
total = 0
X = np.arange(0, n + 1)
p = np.zeros(n + 1, dtype=float)
profit = np.zeros(n + 1, dtype=float)
for i in range(1, n + 1):
p[i] = binom.pmf(X[i], n, 19/20)
if X[i] > 100:
profit[i] = 50 * n - 60 * (X[i] - 100)
else:
profit[i] = 50 * n
total += profit[i] * p[i]
expected_profit(10)

Generalized Distance Transform in Python

I'm currently trying to implement the GDT described by Felzenszwalb and Huttenlocher (http://www.cs.cornell.edu/~dph/papers/dt.pdf) inside of Python for an image processing algorithm. However I used the algorithm described in the paper they published a few years back but got faulty results. I found a C# implementation here: https://dsp.stackexchange.com/questions/227/fastest-available-algorithm-for-distance-transform/29727?noredirect=1#comment55866_29727
And converted it to Python (which is pretty much the same I had before).
This is my code:
def of_column(dataInput):
output = zeros(dataInput.shape)
n = len(dataInput)
k = 0
v = zeros((n,))
z = zeros((n + 1,))
v[0] = 0
z[0] = -inf
z[1] = +inf
s = 0
for q in range(1, n):
while True:
s = (((dataInput[q] + q * q) - (dataInput[v[k]] + v[k] * v[k])) / (2.0 * q - 2.0 * v[k]))
if s <= z[k]:
k -= 1
else:
break
k += 1
v[k] = q
z[k] = s
z[k + 1] = +inf
k = 0
for q in range(n):
while z[k + 1] < q:
k += 1
output[q] = ((q - v[k]) * (q - v[k]) + dataInput[v[k]])
return output
I still can't find my error. When giving the algorithm a binary (boolean) numpy array it just returns the array itself not the Distance Transform. Why is this not working in Python?
I got it working after hours and hours. The answer given in the link above implementing the code in C# suggests putting up the "white" areas to a very large number. My dataInput array was a boolean array (0, 1). I replaced all 1s with 2^32 and it works just fine. The higher the number the more blurry it gets. The lower the more similar to the source it gets.
I would like to add the function for 2D that works with the 1D function described previously:
###############################################################################
# distance transform of 1d function using squared distance
###############################################################################
def dt_1d(dataInput, n):
output = np.zeros(dataInput.shape)
k = 0
v = np.zeros((n,))
z = np.zeros((n + 1,))
v[0] = 0
z[0] = -np.inf
z[1] = +np.inf
for q in range(1, n):
s = (((dataInput[q] + q * q) - (dataInput[v[k]] + v[k] * v[k])) / (2.0 * q - 2.0 * v[k]))
while s <= z[k]:
k -= 1
s = (((dataInput[q] + q * q) - (dataInput[v[k]] + v[k] * v[k])) / (2.0 * q - 2.0 * v[k]))
k += 1
v[k] = q
z[k] = s
z[k + 1] = +np.inf
k = 0
for q in range(n):
while z[k + 1] < q:
k += 1
value = ((q - v[k]) * (q - v[k]) + dataInput[v[k]])
if value > 255: value = 255
if value < 0: value = 0
output[q] = value
print output
return output
###############################################################################
# distance transform of 2d function using squared distance
###############################################################################
def dt_2d(dataInput):
height, width = dataInput.shape
f = np.zeros(max(height, width))
# transform along columns
for x in range(width):
f = dataInput[:,x]
dataInput[:,x] = dt_1d(f, height)
# transform along rows
for y in range(height):
f = dataInput[y,:]
dataInput[y,:] = dt_1d(f, width)
return dataInput
I hope it helps.

Categories

Resources