Trapezoidal rule in Python - python

I'm trying to implement the trapezoidal rule in Python 2.7.2. I've written the following function:
def trapezoidal(f, a, b, n):
h = float(b - a) / n
s = 0.0
s += h * f(a)
for i in range(1, n):
s += 2.0 * h * f(a + i*h)
s += h * f(b)
return s
However, f(lambda x:x**2, 5, 10, 100) returns 583.333 (it's supposed to return 291.667), so clearly there is something wrong with my script. I can't spot it though.

You are off by a factor of two. Indeed, the Trapezoidal Rule as taught in math class would use an increment like
s += h * (f(a + i*h) + f(a + (i-1)*h))/2.0
(f(a + i*h) + f(a + (i-1)*h))/2.0 is averaging the height of the function at two adjacent points on the grid.
Since every two adjacent trapezoids have a common edge, the formula above requires evaluating the function twice as often as necessary.
A more efficient implementation (closer to what you posted), would combine common terms from adjacent iterations of the for-loop:
f(a + i*h)/2.0 + f(a + i*h)/2.0 = f(a + i*h)
to arrive at:
def trapezoidal(f, a, b, n):
h = float(b - a) / n
s = 0.0
s += f(a)/2.0
for i in range(1, n):
s += f(a + i*h)
s += f(b)/2.0
return s * h
print( trapezoidal(lambda x:x**2, 5, 10, 100))
which yields
291.66875

The trapezoidal rule has a big /2 fraction (each term is (f(i) + f(i+1))/2, not f(i) + f(i+1)), which you've left out of your code.
You've used the common optimization that treats the first and last pair specially so you can use 2 * f(i) instead of calculating f(i) twice (once as f(j+1) and once as f(i)), so you have to add the / 2 to the loop step and to the special first and last steps:
s += h * f(a) / 2.0
for i in range(1, n):
s += 2.0 * h * f(a + i*h) / 2.0
s += h * f(b) / 2.0
You can obviously simplify the loop step by replacing the 2.0 * … / 2.0 with just ….
However, even more simply, you can just divide the whole thing by 2 at the end, changing nothing but this line:
return s / 2.0

Related

Seemingly arbitrary result when multiplying complex numbers

I'm trying to understand how complex numbers get multiplied. when I multiply two numbers it always seems to give me an arbitrary amount. for example,
complex(10,9)*complex(11,13) equals complex(-7,229)and complex(10,1)*complex(10,2) equals complex(98,30). is there a mathematical way to figure out 2 complex numbers multiplied and if so, what is is it?
The result is not arbitrary, it is following the definition of complex multiplication:
For example if you have
x = a + j * b
y = c + j * d
then the expression for multiplication is
x * y = (a * c - b * d) + j (a * d + b * c)
For your example complex(10,9) * complex(11,13) that would evaluate to
(10 * 11 - 9 * 13) + j * (10 * 13 + 9 * 11)
(-7 + 229j)
which is exactly what Python shows
>>> complex(10,9) * complex(11,13)
(-7+229j)
Complex number multiplication operates in this way:
(a + ib) * (c + id) = a * c + a * id + ib * c + ib * id
= a * c - b * d + i(a * d + b * c)
So, in Python, the result is like this:
complex(a, b) * complex(c, d) = complex(a * c - b * d, a * d + b * c)
Example:
complex(10, 9) * complex(11, 13) = complex(10 * 11 - 9 * 13, 10 * 13 + 9 * 11)
= complex(-7, 227)
If you have 2 complex numbers, the first a + bj, and the second c + dj, then the product (a + bj) * (c + dj) = a*c - b*d + (a*d + b*c)j. The way to think about it is that j is equal to the square root of -1, so j*j = -1, and then just multiply out the brackets as normal. See below:
a, b = 10, 9
c, d = 11, 13
print(complex(a, b)*complex(c, d))
print(a*c - b*d, a*d + b*c)
Output:
(-7+229j)
-7 229
Another way to understand complex number multiplication is geometrically. We can think of complex numbers as two dimensional vectors, things with a length and direction. Then when multiplying a complex number with length r and direction a by another with length s and direction b, you get a complex number with length r*s and direction a+b, i.e. a complex number with length r and direction a acts on others by multiplication by scaling them by r and rotating them through a.
If you work out the lengths and directions of your (10,9) and (11,13) and combine them as above, you will get the length and direction of (-7,229)

How to make this float precision without using print

I'm working on assignment, it's about numerical method regarding to trapezoidal rule
def trapezoidalRule(F,a,b,n):
h = float(b-a)/n
f_sum = 0
for i in range(1, n, 1):
x = a + i * h
f_sum = f_sum + f(x)
return h * (0.5 * f(a) + f_sum + 0.5 * f(b))
def f(x):
return x**3
a = 2
b = 10
n = 512
print('%.16f' %trapezoidalRule(f, a, b, n))
And the output is
2496.0058593750000000
My question is, how do i get a precission like that.. without using print('%.16f' %trapezoidalRule(f, a, b, n)). I want to append the result to the list, with exact value like that..
I already tried to google it, but i found nothing related to this problem, can somebody tell me the solution if i want to it ?
Change your return statement in trapezoidalRule to be formatted with 16 points of precision, do note that this is going to cause it to become a string as if you cast it back to float you'll lose the trailing 0's.
def trapezoidalRule(F,a,b,n):
h = float(b-a)/n
f_sum = 0
for i in range(1, n, 1):
x = a + i * h
f_sum = f_sum + f(x)
return format((h * (0.5 * f(a) + f_sum + 0.5 * f(b))), '.16f')
def f(x):
return x**3
a = 2
b = 10
n = 512
See the return line in trapezoidalRule so now if I print the exact output of trapezoidalRule like so: print(trapezoidalRule(f, a, b, n)) with no formatting I get:
2496.0058593750000000
To increase precision try using decimal module
import decimal
def trapezoidalRule(F,a,b,n):
h = decimal.Decimal(float(b-a)/n)
f_sum = 0
for i in range(1, n, 1):
x = a + i * h
f_sum = f_sum + f(x)
return h * (decimal.Decimal(0.5) * f(a) + f_sum + decimal.Decimal(0.5) * f(b))
def f(x):
return decimal.Decimal(x**3)

How to optimize a algorithm that uses loops to find a stable value for a variable

I have a case where a variable (a, in this case) is calculated at each loop iteration and stops where the increment of value between two iterations is small enough.
I would like to know of a general way to find the value for that variable in this kind of case, without having to do that "convergence" work using loops.
There I would like to know if the solution is to put everything in equations, or if some tools exist to tackle that.
a = 10
b = 10
diff = 1
while diff > .1:
old_a = a
a += b
diff = 1 - (old_a/a)
print(diff)
The present code produces:
0.5
0.33333333333333337
0.25
0.19999999999999996
0.16666666666666663
0.1428571428571429
0.125
0.11111111111111116
0.09999999999999998
Therefore, it takes 9 iterations to find a relative difference of the value of a between two iterations inferior to 10%.
You have
a_n = a_0 + n * b
and try to find where
1 - (a_(n-1) / a_n)
= 1 - (a_0 + (n--1)*b) / ( a_0 + n * b)
= 1 - (a_0 + n*b -b) / (a_0 + n*b)
= 1 - 1 + b / (a_0 + n*b)
= b / (a_0 + n * b)
< 0.1
That is the same as
(a_0 / b) + n * b / b
= (a_0 / b) + n
> 10
(because 0.1 = 1 / 10 and 1/x > 1/y <=> y > x if x,y != 0)
Since you metion in the comments that your actual problem is more complex: If finding a closed form solution like above is not feasible, look at this wikipedia page about fixed point iteration, which is exactly the kind of problem you try to solve.

Simpson's Rule Takes Forever to Run in Python

I've written the following function for estimating the definite integral of a function with Simpson's Rule:
def fnInt(func, a, b):
if callable(func) and type(a) in [float] and type(b) in [float]:
if a > b:
return -1 * fnInt(func, b, a)
else:
y1 = nDeriv(func)
y2 = nDeriv(y1)
y3 = nDeriv(y2)
y4 = nDeriv(y3)
f = lambda t: abs(y4(t))
k = f(max(f, a, b))
n = ((1 / 0.00001) * k * (b - a) ** 5 / 180) ** 0.25
if n > 0:
n = math.ceil(n) if math.ceil(n) % 2 == 0 else math.ceil(n) + 1
else:
n = 2
x = (b - a) / n
ans = 0
for i in range(int((n - 4) / 2 + 1)):
ans += (x / 3) * (4 * func(a + x * (2 * i + 1)) + 2 * func(a + x * (2 * i + 2)))
ans += (x / 3) * (func(a) + 4 * func(a + x * (n - 1)) + func(b))
return ans
else:
raise TypeError('Data Type Error')
It seems, however, that whenever I try to use this function, it takes forever to produce an output. Is there a way that I can rewrite this code in order to take up less time?
As one of the comments mentioned, profiling the code will show you the slowdowns. Perhaps nDeriv is slow. If you don't have a profiling tool, you can put time() calls around each section of code and print the results. More info here: Measure time elapsed in Python?
So, if the slowdown ends up being in your for loop, here are a few things you can try:
Python might be computing the loop condition every iteration:
for i in range(int((n - 4) / 2 + 1)):
calculate int((n - 4) / 2 + 1) once before the loop.
Don't recalculate stuff inside the loops that doesn't change. For example, x / 3 is going to be recalculated every loop iteration, but it never changes. Do it before the loop starts.
Likewise, you're doing 2 * i twice every loop iteration.
Addition is faster than multiplication. The func arguments could be re-written as:
xi = x * i
a1 = a + xi + xi + x
a2 = a1 + x
and then taking it a step further, you could also re-do xi as an accumulator. That is, start with x = 0, then every iteration simply x += x
This is probably obvious, but if func() is difficult to calculate, this function will be exponentially slow.
Python may be doing a lot of simpler optimizations for you, so these may not help, but just wanted to share some ideas.

how to solve integration using simpsons rule in python?

I have the following assignment: Si(x) = the integral from 0 to x of sin(t)/t. Write a python code that takes the parameter x and returns the sine integral for that x.
I cant figure out how to move forward with my code to make it work. Can anyone help me?
I get this error:
Traceback (most recent call last):
File "C:\Users\krist_000\Desktop\integration_simpson.py", line 37, in <module>
print(simpsons_rule( f_of_t, 2, b, N))
File "C:\Users\krist_000\Desktop\integration_simpson.py", line 18, in simpsons_rule
I += f(t) + (2.0*f(t+h) )
UnboundLocalError: local variable 't' referenced before assignment
[Finished in 0.1s with exit code 1]
Here is my code:
def simpsons_rule( f, x, b, N):
*""" Implements simpsons_rule
f(t) - function to integrate
x - start point
b - end point
N - number of intervals, must be even.
"""*
if N & 1:
print ("Error: N is not a even number.")
return 0.0
h = (b - x) / N
I = 0.0
x = float(x)
for i in range(0, N/2):
I += f(t) + (2.0*f(t+h) )
t += 2*h
I = (2.0 * I) - f(x) + f(b)
I = h * I / 3.0
return I
import math
def f_of_t(t):
return (math.sin(t)) / t
N = 1000
b = 0.0
print(simpsons_rule( f_of_t, 2, b, N))
PyCharm found a few problems with your code. Your code compiles and runs now. I get the correct answer, according to Wolfram Alpha:
F:\Tools\python-2.7.3\python.exe F:/Projects/Python/udacity/udacity/simpsons.py
1.6054029768
Process finished with exit code 0
See if this works better for you. You would do well to study the changes I made and understand why I made them:
def simpsons_rule(f, a, b, n):
"""
Implements simpsons_rule
:param f: function to integrate
:param a: start point
:param b: end point
:param n: number of intervals, must be even.
:return: integral of the function
"""
if n & 1:
print ("Error: n is not a even number.")
return 0.0
h = float(b - a) / n
integral = 0.0
x = float(a)
for i in range(0, n / 2):
integral += f(x) + (2.0 * f(x + h))
x += 2 * h
integral = (2.0 * integral) - f(a) + f(b)
integral = h * integral / 3.0
return integral
import math
def f_of_t(t):
# Note: guard against singular behavior at t = 0.
# L'Hospital says value should be 1.0. NAN if you don't check.
if x == 0:
return 1.0
else:
return (math.sin(t)) / t
n = 10000
a = 0
b = 2
print(simpsons_rule(f_of_t, a, b, n))

Categories