Why do I keep getting a float division by zero in Python? - python

I have written the following code:
import math
import scipy
def steffensen(equation, f_prime, x, er, N):
for i in range(1, N):
y1 = x
r = equation(x)
dx = (-r)/(f_prime(x))
y2 = y1 + dx
y3 = y2 + dx
x = y1-(((y2-y1)**2)/(y3-2*y2+y1))
z = abs(equation(x))
print("|f(x)| = %e"%z)
if z < e:
print("Converged!")
break
return x
#This will be used for testing
def equation(x):
return math.exp(-x**2 + x)-(0.5*x)
def f_prime(x):
return (1-2*x)*math.exp(x-(x**2))-0.5
#def main():
x0 = 1
N = 5
er = 1e-6
x = steffensen(equation, f_prime, x0, er, N)
print("Finished!")
When compiled, the code returns saying that there is a zero division error: float division by zero on the line that says: x = y1-(((y2-y1)**2)/(y3-2*y2+y1)). When computed by hand, I don't get 0. Please help me find the bug.

You're getting a zero division error because your program divides by zero. The question you should focus on is "how do I figure out what's wrong?" Do it by adding a diagnostic statement just before the line that throws the error. I'd start with this one:
print(i, dx, y1, y2, y3, y3-2*y2+y1)
You'll get this output,
1 0.3333333333333333 1 1.3333333333333333 1.6666666666666665 0.0
showing that the error occurs on the first pass through the loop (i == 1), and that dx has the value 1/3. Take it from there, and figure out why your program diverges from the calculation you did by hand.

Related

Calculating volume of a 2 variable definite integral using the midpoint rule of Riemann Summs

I am trying to approximate the volume of a 2 variable definite integral sin^2(x)-cos^2(y) using while and for loops. I've changed the code quite often and with the most recent change, it broke. I am very new to python so I'm still figuring out how to work with arrays properly.
This is what I have untill now (EDIT: With alani's comment I managed to fix the error, but now I'm not receiving an answer when running the code)
import numpy as np
import scipy.integrate
def f(x,y):
return np.sin(x)**2-np.cos(y)**2
print(scipy.integrate.dblquad(f,0,1,0,2))
def Riemann(x0,xn,y0,yn,N):
e = 1;
while e > 1e-3:
x = np.linspace(0,1,N)
y = np.linspace(0,2,N)
dx = (x0-xn)/N
dy = (y0-yn)/N
for i in range(N):
V = (dx*dy)*(f(x,y))
np.sum(V)
e = abs(1-V)
print(Riemann(0,1,0,2,1000))
When running this code I receive:
(-0.2654480895858587, 9.090239973208559e-15)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-9-c654507b2f73> in <module>
19 np.sum(V)
20 e = abs(1-V)
---> 21 print(Riemann(0,1,0,2,10))
22
23
<ipython-input-9-c654507b2f73> in Riemann(x0, xn, y0, yn, N)
10 def Riemann(x0,xn,y0,yn,N):
11 e = 1;
---> 12 while e > 1e-3:
13 x = np.linspace(0,1,N)
14 y = np.linspace(0,2,N)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Your code has multiple issues, I'll address them so that you can improve. First off all, the formatting is pretty terrible. Put spaces after commas, separate things more with white-space, etc. You can see the difference in my code, and I'm by no means an expert at code formatting.
Second, your method is not doing what you think it's doing. Every time you iterate i, you create an entire array of values and you assign it to V, since x and y are both arrays. Neither x nor y are being updated here. The loop does the same thing every time, and V get re-assigned the same value every time. np.sum(V) never gets assigned anywhere, so the only thing getting updated at all in that loop is e. Of course, that bit is incorrect since you cannot subtract a vector from a scalar, since, as I wrote above, V is a vector.
Your function didn't use x0, y0, etc. for your bounds of integration, since your linspaces were hardcoded.
Now we come to the solution. There are two approaches to this problem. There's the "slow" pure Python way, where we just loop over our y's and x's and take function values multiplied by the base dx * dy. That version looks like this:
# This a naive version, using two for loops. It's very slow.
def Riemann(x0, xn, y0, yn, N):
xs = np.linspace(x0, xn, N)
ys = np.linspace(y0, yn, N)
dx = (x0 - xn) / N
dy = (y0 - yn) / N
V = 0
for y in ys:
for x in xs:
V += f(x, y)
return dx * dy * V
Note I moved the multiplication outside to save some on performance.
The other way is to use numpy, that version looks like this:
def Riemann(x0, xn, y0, yn, N):
points = itertools.product(np.linspace(x0, xn, N), np.linspace(y0, yn, N))
points = np.array(list(points))
xs = points[:, 0]
ys = points[:, 1]
dx = (x0 - xn) / N
dy = (y0 - yn) / N
return dx * dy * np.sum(f(xs, ys))
Here we avoid the double for-loop. Note that you must include import itertools for this to work. Here we use the Cartesian product to create all points we wish to evaluate, and then give those points to your function f which is designed to work with numpy arrays. We get a vector back from f of all the function values at each point, and we simply just sum all the elements, just like we did in the for-loop. Then we can multiply by the common base dx * dy and return that.
The only thing I do not understand about your code is what you want e to do, and how it relates to N. I'm guessing it's some sort of error tolerance, but why you were trying to subtract the total volume so far (even if your code did nothing of the sort) from 1 I can't understand.

drawing a jagged mountain curve using turtle-graphics and recursion

I am trying to create a function for a homework assignment which draws a jagged mountain curve using turtles and recursion. The function is called jaggedMountain(x,y,c,t) where x x,y are end coordinates, c is a complexity constant, and t is the turtle object. I am trying to create an image like this:
def jaggedCurve(x,y,c,t):
t.pendown()
x1 = t.xcor() + x / 2
y1 = t.ycor() + y / 2
y1 = y + (random.uniform(0,c)-0.5) * (t.xcor() - x)
if (x1,y1) == (x,y):
return None
else:
jaggedCurve(x1,y1,c,t)
This crashes quickly as the base case never executes, the function is called 993 times, and the recursion depth is exceeded. I have been scratching my head with this for quite some time, are there any suggestions?
Initially, I see two issues with your code. The first is:
if (x1,y1) == (x,y):
Turtles wander a floating point plane, the odds of these being exactly equal is small. You're likely better off doing something like:
def distance(x1, y1, x2, y2):
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
...
if distance(x1, y1, x, y) < 1.0:
The second issue is that jaggedCurve() draws nothing nor returns anything that can be used for drawing. Somewhere you need to actually move the turtle to cause something to be drawn.
Finally, though it's hard to be certain without a value for c, my guess is even with the above changes you won't get you what you want. Good luck.
Very interesting problem!
My solution is to make a recursive function that draws a mountain curve given two end points. Randomly pick a x coordinate value that lies in between two end points and compute the range of possible y coordinate given the maximum possible slope and randomly pick a y value in between this range and do this recursively. When to end points are close enough, just draw the line between them. Here is the code:
MAX_SLOPE = 45
MIN_SLOPE = -45
MIN_HEIGHT = 0
def dist_squared(P1,P2):
return (P1[0]-P2[0])**2 + (P1[1]-P2[1])**2
def mountain(P1,P2):
if dist_squared(P1,P2) < 1:
turtle.goto(P2)
return
x1,y1 = P1
x2,y2 = P2
x3 = random.uniform(x1,x2)
y3_max = min((x3-x1)*math.tan(math.radians(MAX_SLOPE)) + y1, (x2-x3)*math.tan(-math.radians(MIN_SLOPE)) + y2)
y3_min = max((x3-x1)*math.tan(math.radians(MIN_SLOPE)) + y1, (x2-x3)*math.tan(-math.radians(MAX_SLOPE)) + y2)
y3_min = max(y3_min, MIN_HEIGHT)
y3 = random.uniform(y3_min,y3_max)
P3 = (x3, y3)
mountain(P1,P3)
mountain(P3,P2)
return
turtle.up()
turtle.goto(-400,0)
turtle.down()
mountain((-400,0),(400,0))
I know this was posted like 3 months ago, but hopefully this is helpful to someone that was also assigned this terrible problem 5 days before finals! Ha!
The struggle I had with this problem was not realizing that you only need to pass in one point. To get the point the turtle is starting at, you just use .xcor() and .ycor() that are included in the turtle library.
import turtle
import random
def mountain (x, y, complexity, turtleName):
if complexity == 0:
turtleName.setposition(x, y)
else:
x1 = (turtleName.xcor() + x)/2
y1 = (turtleName.ycor() + y)/2
y1 = y1 + (random.uniform(0, complexity) - 0.5) * (turtleName.xcor() - x)
complexity = complexity - 1
mountain(x1, y1, complexity, turtleName)
mountain(x, y, complexity, turtleName)
def main ():
#Gets input for first coordinate pair, splits, and assigns to variables
coordinate = str(input("Enter the coordinate pair, separated by a comma: "))
x, y = coordinate.split(',')
x = int(x)
y = int(y)
complexity = int(input("Enter the complexity: "))
while complexity < 0:
complexity = int(input("Input must be positive. Enter the complexity: "))
Bob = turtle.Turtle()
mountain(x, y, complexity, Bob)
main ()

Root Finding Function for upper and lower intersections of the x-axis

I need to find the lower and upper intersections with the x-axis of a curve given by
y=f(x)=10⋅exp(sin(x))−(x^2)/2
In order to find the arc length of the curve, in Python
I have already tried two methods, The secant method which I cannot get to work at all. And the Newton Method which finds one intersection.
from math import exp
from math import sin
from math import cos
def func( x ):
return 10*exp(sin(x))-(x**2)/2
def derivFunc( x ):
return 10*exp(sin(x))*cos(x)-x
def newtonRaphson( x ):
h = func(x) / derivFunc(x)
while abs(h) >= 0.0001:
h = func(x)/derivFunc(x)
x = x - h
print("The value of the root is : ",
"%.4f"% x)
x0 = -20
newtonRaphson(x0)
which gives
The value of the root is : -5.7546
Then the second method
import math
from math import exp
from math import sin
def f(x):
f = 10*exp(sin(x))-(x**2)/2
return f;
def secant(x1, x2, E):
n = 0; xm = 0; x0 = 0; c = 0;
if (f(x1) * f(x2) < 0):
while True:
x0 = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
c = f(x1) * f(x0);
x1 = x2;
x2 = x0;
n += 1;
if (c == 0):
xm = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
if(abs(xm - x0) < E):
print("Root of the given equation =",round(x0, 6));
print("No. of iterations = ", n);
print("Can not find a root in ","the given inteval");
x1 = 0; x2 = 1;
E = 0.0001;
secant(x1, x2, E);
Only results in
NameError: name 'x2' is not defined
Yet whenever I've tried defining the characters it won't run
I would like to be able to get the upper and lower intersections with the x-axis, So I can find the arc length. And is there a way to get it to plot the graph as well
About the Newton-Raphson method:
Normal behaviour
It works mostly as intended. The method may converge to a single root only, which depends on the starting point. To get another root, you need another starting point.
Your function yields:
>>> newtonRaphson(-20)
-5.7545790362989
>>> newtonRaphson(5)
3.594007784799419
Which seems to be correct.
Bugs
The Newton-Raphson method isn't guaranteed to converge, it may enter an ifinite loop, in which case your program would hang indefinitely, or the derivative at a point may be zero, in which case you can't compute h. You need to handle these cases.
Style
There is a lot of things that can be inproved:
The bug must be fixed
You Newton-Raphson method currently only works for one function only. You should pass the function and derivative as arguments, so you can apply the method to any function you want.
The desired precision and max iterations can also be passed as arguments
It's bad practice to print within the function. You should return the value instead, so you can decide to do whatever with the result.
you should follow PEP8's style guidelines
include a docstring if you plan to reuse it (wich is very possible, it is a very useful tool!)
My take on the method:
def newton_raphson(f, df, x, epsilon = 0.0001, maxiter = 1000):
""" Estimates the root of a function.
Gives an estimate to the required precision of a root of the given function
using the Newton-Raphson method.
Raises an Exception if the Newton-Raphson method doesn't converge in the
specified number of iterations.
Raises a ZeroDivisionError if the derivative is zero at a calculated point
:param f: The function
:param df: The function's derivative
:param x: the starting point for the method
:param epsilon: The desired precision
:param maxiter: The maximum number of iterations
:return: The root extimate
:rtype: float
"""
for _ in range(maxiter):
h = f(x)/df(x)
if abs(h) < epsilon:
return x
x = x - h
raise Exception("Newton Raphson method didn't "
+ "converge in {} iterations".format(maxiter))
usage:
>>> print(newton_raphson(func, derivFunc, 20))
-5.7545790362989
>>> print(newton_raphson(func, derivFunc, 5, 0.1, 100))
3.5837828560043477
>>> print(newton_raphson(func, derivFunc, 5, 0.001, 100))
3.594007784799419
>>> print(newton_raphson(func, derivFunc, 5, 1e-9, 4))
Traceback (most recent call last):
(...)
Exception: Newton Raphson method didn't converge in 4 iterations
About the secant method:
I'm not as familiar with that one, so I'll just mention the error you have is due to bad identation. Here it is fixed:
def secant(x1, x2, E):
n = 0; xm = 0; x0 = 0; c = 0;
if (f(x1) * f(x2) < 0):
while True:
x0 = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
c = f(x1) * f(x0);
x1 = x2;
x2 = x0;
n += 1;
if (c == 0):
xm = ((x1 * f(x2) - x2 * f(x1)) /(f(x2) - f(x1)));
if(abs(xm - x0) < E):
print("Root of the given equation =",round(x0, 6));
print("No. of iterations = ", n);
print("Can not find a root in ","the given inteval");
If you plan to propely implement this method, the remarks about the Newton-Raphson method still hold.

implement an integration math equation using odeint in Python

I am trying to solve the following equation in python using the scipy.odeint function.
Currently I am able to implement this form of the equation
in python using the following script:
def dY(y1, x):
a = 0.001
yin = 1
C = 0.01
N = 1
dC = C/N
b1 = 0
return (a/dC)*(yin-y1)+b1*dC
x = np.linspace(0,20,1000)
y0 = 0
res = odeint(dY, y0, x)
plt.plot(t,res, '-')
plt.show()
My problem with the first equation is 'i'. I don't know how to integrate the equation and still be able to provide the current and previous 'y'(yi-1 and yi) values. 'i' is simply a sequence number that is within a range of 0..100.
Edit 1:
The original equation is:
Which I rewrote using y,x,a,b and C
Edit2:
I edited Pierre de Buyl' code and changed the N value. Luckily I have a validation table to validate the outcome against. Unfortunately, the results are not equal.
Here is my validation table:
and here is the numpy output:
Used code:
def dY(y, x):
a = 0.001
yin = 1
C = 0.01
N = 3
dC = C/N
b1 = 0.01
y_diff = -np.copy(y)
y_diff[0] += yin
y_diff[1:] += y[:-1]
return (a/dC)*(y_diff)+b1*dC
x = np.linspace(0,20,11)
y0 = np.zeros(3)
res = odeint(dY, y0, x)
plt.plot(x,res, '-')
as you can see the values are different by an offset of 0.02..
Am I missing something that results in this offset?
The equation is a "coupled" ordinary differential equation (see "System of ODEs" on Wikipedia.
The variable is a vector containing y[0], y[1], etc. To solve the ODE you must feed a vector as the initial condition and the function dY must return a vector as well.
I have modified your code to achieve this result:
def dY(y, x):
a = 0.001
yin = 1
C = 0.01
N = 1
dC = C/N
b1 = 0
y_diff = -np.copy(y)
y_diff[0] += yin
y_diff[1:] += y[:-1]
return (a/dC)*y_diff+b1*dC
I have written the part y[i-1] - y[i] as a NumPy vector operation and special cased the coordinate y[0] (that is the y1 in your notation but arrays start at 0 in Python).
The solution, using an initial value of 0 for all yi is
x = np.linspace(0,20,1000)
y0 = np.zeros(4)
res = odeint(dY, y0, x)
plt.plot(x,res, '-')

defining integral using trapezoidal rule(beginner)

My programm aims in defining the integral of a given function between two numbers (x1,x2),using n trapezoids.As it seems,my department's auto evaluating programm gives different answers than the ones of mine.Problem is that i cant find anything wrong in my code...
def funct(x):
val= -(1./6)*(x-1)*(x-2)*(x+2)*(x-4)
return val
x1,x2,n=input()
Dx=float(x2-x1)/n
Sum=0
i=x1+Dx
while i<x2:
val=funct(i)
Sum+=val
i+=Dx
Sum=2*Sum
val1=funct(x1)
val2=funct(x2)
S=(Dx/2)*(val1+val2+Sum)
print "%.3f" %S
Due to rounding issues, your while cycle always includes last value of x, try using exact integer arithmetic
x0, x1 = -88.787529, 83.494648
n = 1942
dx = (x1-x0)/n
s = 0
i = 1
while i < n:
# if we allow i == n, in the following row we'll have
# x0 + n*dx = x0 + n * (x1-x0) / n = x0 + x1 - x0 = x1
# but we want to exclude the last term
s = s + funct(x0+i*dx)
i = i + 1
result = (s + funct(x0)/2.0 + funct(x1)/2.0)*dx
I know this is probably some sort of homework question, but in general, don't reinvent the wheel:
import numpy
def funct(x):
return -(1./6)*(x-1)*(x-2)*(x+2)*(x-4)
x1, x2 = -88.787529, 83.494648
n = 1942
# n "panels", n+1 points
x = numpy.linspace(x1, x2, n+1)
y = funct(x)
result = numpy.trapz(y, x)

Categories

Resources