Programming & Numerical Analysis: Kai-Feng Chen
Programming & Numerical Analysis: Kai-Feng Chen
PROGRAMMING &
NUMERICAL ANALYSIS 16
Lecture 07:
0 2
Numerical Differential and Integration
1
ANALYTICAL VERSUS
NUMERICAL
A GENERAL RULE:
■ If you know the exact form, it's always better to do the calculus
analytically unless it's not really doable.
■ Although we could do the calculation numerically without a
problem, but the precision is always a big issue.
■ In this lecture, we will discuss the derivatives & integration for a
black box function f(x).
f (x) =
2
ANALYTICAL VERSUS
NUMERICAL
ON THE OTHER HAND:
■ Even if you can do your derivatives or integrations analytically, it
is still very useful to do the same thing in a numerical way as a
very good cross check (ie. debug).
■ Suppose, you have >50 different functions to be implement in your
code, and you are calculating their derivatives analytically, even
you have already calculated everything by yourself, but it does
not guarantee you have no typo in your code!
3
NUMERICAL DERIVATIVES
■ Suppose, you have a function f(x), and now you want to compute
f’(x), it’s pretty easy, right?
0 f (x + h) f (x)
By definition, for h → 0 f (x) ⇡
h
■ In principle we could insert a small h, maybe as small as possible
under the conversion of the numerical calculations. But THIS IS
NOT TRUE for numerical derivatives.
■ So, let's try such a simple function that we could actually do the
exact calculations easily:
f (x) = x2 + exp(x) + log(x) + sin(x)
0 1
f (x) = 2x + exp(x) + + cos(x)
x
4
LET'S GIVE IT A QUICK TRY!
import math
def f(x):
return x**2+math.exp(x)+math.log(x)+math.sin(x)
def fp(x):
return 2.*x+math.exp(x)+1./x+math.cos(x)
while h>1E-15:
fp_numeric = (f(x+h) - f(x))/h
print 'h = %e' % h
print 'Exact = %.16f,' % fp_exact,
print 'Numeric = %.16f,' % fp_numeric,
print 'diff = %.16f' % abs(fp_numeric-fp_exact)
h /= 10.
⇐ retry with smaller h!
l7-example-01.py
5
A QUICK TRY...?
■ Output:
Exact = 5.5263038325905010
6
OK, WHAT’S THE PROBLEM?
7
THE PROBLEM?
8
THE TRICK IS
ACTUALLY VERY SIMPLE...
h h 0 h2 00 h3 000
f (x + ) ⇡ f (x) + f (x) + f (x) + f (x) + ...
2 2 8 48
h h 0 h2 00 h3 000
f (x ) ⇡ f (x) f (x) + f (x) f (x) + ...
2 2 8 48
2 ⇣✏ ⌘
0 f (x + h2 ) f (x h
2 ) 0 h 000 4 m
fnumerical (x) ⇡ ⇡ f (x) + f (x) + O(h )... + O
h 24 h
⇣✏ ⌘ ✓ 16
◆
2 m 2 10
The total error ~ O(h ) + O ⇡ O(h ) +
h h
The total error will saturation at O(10–10) if h ⇡ O(✏1/3
m ) ⇡ O(10
5
)
9
A QUICK TRY AGAIN!
import math
def f(x):
return x**2+math.exp(x)+math.log(x)+math.sin(x)
def fp(x):
return 2.*x+math.exp(x)+1./x+math.cos(x)
x, h = 0.5, 1E-2
fp_exact = fp(x)
while h>1E-15:
fp_numeric = (f(x+h/2.) - f(x-h/2.))/h ⇐ Update here
print 'h = %e' % h
print 'Exact = %.16f,' % fp_exact,
print 'Numeric = %.16f,' % fp_numeric,
print 'diff = %.16f' % abs(fp_numeric-fp_exact)
h /= 10.
l7-example-01a.py
10
A QUICK TRY AGAIN! (II)
■ Output:
Exact = 5.5263038325905010
11
A FURTHER
IMPROVEMENT
■ Let's repeat the trick of “cancellation”:
h h 0 h2 00 h3 000
f (x + ) ⇡ f (x) + f (x) + f (x) + f (x) + ...
4 4 32 384
h h 0 h2 00 h3 000
f (x ) ⇡ f (x) f (x) + f (x) f (x) + ...
4 4 32 384
f (x + h4 ) f (x h
4) 1 0 h2 000
⇡ f (x) + f (x) + O(h4 )...
h 2 192
f (x + h2 ) f (x h
2) h 2
⇡ f 0 (x) + f 000 (x) + O(h4 )...
h 24
12
A FURTHER
IMPROVEMENT (II)
"
■ Then # " #
f (x + h4 ) f (x h
f (x + h2 ) h ⇥ ⇤ ⇣✏ ⌘
4) f (x 2) m
8 ⇡ 3f 0 (x) + O(h4 )... + O
h h h
0
fnumerical (x) ⇡
8f (x + h4 ) 8f (x h
f (x + h2 ) + f (x h ⇥ ⇤ ⇣✏ ⌘
4) 2) m
+ O(h4 )... + O
3h h
Take this term and neglect the rest
⇣✏ ⌘ ✓ 16
◆
4 m 4 10
The total error ~ O(h ) + O ⇡ O(h ) +
h h
1/5 3
The total error will saturation at O(10–13) if h ⇡ O(✏ m ) ⇡ O(10 )
13
JUST CHANGE A LINE...
import math
def f(x):
return x**2+math.exp(x)+math.log(x)+math.sin(x)
def fp(x):
return 2.*x+math.exp(x)+1./x+math.cos(x)
x, h = 0.5, 1E-2
fp_exact = fp(x)
while h>1E-15:
fp_numeric = \ ⇙ Update here (note: a backslash “\” can wrap a python line)
(8.*f(x+h/4.)+f(x-h/2.)-8.*f(x-h/4.)-f(x+h/2.))/(h*3.)
print 'h = %e' % h
print 'Exact = %.16f,' % fp_exact,
print 'Numeric = %.16f,' % fp_numeric,
print 'diff = %.16f' % abs(fp_numeric-fp_exact)
h /= 10. l7-example-01b.py
14
JUST CHANGE A LINE...(II)
■ Output:
Exact = 5.5263038325905010
15
INTERMISSION
■ You have learned that the central difference method cancels the
term up to f’’, and the improved higher order method cancels the
term up to f’’’. You may try the code (l7-xample-01a.py and
l7-example-01b.py) and calculate the numerical derivative for
a polynomial up to x2 and x3. Can the calculation be 100% precise
or not?
■ For example you may try such a simple function:
f (x) = 5x3 + 4x2 + 3x + 2
0 2
! f (x) = 15x + 8x + 3
16
NUMERICAL
INTEGRATION
■ Starting from some super basic integration rules:
Rectangle rule
Trapezoidal rule
Simpson's rule
17
NUMERICAL
INTEGRATION (II)
■ Let's practice a classical integration: the trapezoidal rule, e.g.
2 3 4 sin(13x)
f (x) = x x +x x +
Z 13 2
x x3 x4 x5 cos(13x)
f (x)dx = +
2 3 4 5 169
L
xi+1
xi
fi fi+1
h
18
TRAPEZOIDAL RULE:
IMPLEMENTATION
import math
def f(x):
return x - x**2 + x**3 - x**4 + math.sin(x*13.)/13.
def fint(x):
return x**2/2. - x**3/3. + x**4/4. - x**5/5. - math.cos(x*13.)/169.
fint_exact = fint(1.2)-fint(0.)
area, x, h = 0., 0., 1E-3 ⇐ start with h = 10–3
f0 = f1 = f(x)
while x<1.2-h*0.5:
f0, f1 = f1, f(x+h) Exact: 0.1765358676046381,
x += h Numerical: 0.1765352854227494,
area += f0+f1
diff: 0.0000005821818886
area *= h/2.
Exact = 0.1765358676046381
20
ERROR ANALYSIS:
APPROXIMATION ERROR
■ Consider Taylor expansions for f(x): 2 3
h h
f (x + h) ⇡ f (x) + hf 0 (x) + f 00 (x) + f 000 (x) + ...
2 6
Exact integration:Z
h
h2 0 h3 00 h4 000
f (x + ⌘)d⌘ ⇡ hf (x) + f (x) + f (x) + f (x) + ...
0 2 6 24
Trapezoidal rule:
h h2 0 h3 00 h4 000
[f (x) + f (x + h)] ⇡ hf (x) + f (x) + f (x) + f (x) + ...
2 2 4 12
h3 00
Error per interval: ⇡ f (x) + ...
12
L
Approximation error: ✏approx ⇡ O(h ) ⇥ ⇡ O(h2 )
3
h
21
ERROR ANALYSIS:
TOTAL ERROR
■ If we believe theptheory:
L
✏roundo↵ ⇡ O( N ✏m ) N / = total no. of operation steps.
h
■ The total error: p
✓ ◆
2 ✏m
✏total ⇡ O( N ✏m ) + O(h ) ⇡ O p + O(h2 )
h
15 16
For a double precision float point number, ✏m ⇡ O(10 ) O(10 )
The best precision will be of O(10–12) when h ⇡ O(✏1/2.5
m ) ⇡ O(10 6
)
22
AN EASY IMPROVEMENT
■ Another classical method: Simpson's Rule.
■ Instead of liner interpolation, we could use a 2nd-order (parabola)
interpolation along 3 points:
L
xi+2
xi+1
xi
fi fi+1 fi+2
h h
23
THE FORMULAE
■ Treat the function as a parabola between the interval [–1,+1]:
Z +1 +1
a 3 b 2 2a
f (x) ⇡ ax2 + bx + c f (x)dx = x + x + cx = + 2c
1 3 2 1 3
{
f (+1) ⇡ a + b + c Z +1
f ( 1) 4f (0) f (+1)
f (0) ⇡ c Solve a,b,c : f (x)dx = + +
1 3 3 3
f ( 1) ⇡ a b+c
Z 2h
h 4h h
Simpson’s rule: f (x + ⌘)d⌘ ⇡ f (x) + f (x + h) + f (x + 2h)
0 3 3 3
Total integration:
Z
h 4h 2h 4h 2h 4h h
f (x)dx ⇡ f1 + f2 + f3 + f4 + f5 + ... + fN 1 + fN
3 3 3 3 3 3 3
24
SIMPSON’S RULE:
IMPLEMENTATION
import math
def f(x):
return x - x**2 + x**3 - x**4 + math.sin(x*13.)/13.
def fint(x):
return x**2/2. - x**3/3. + x**4/4. - x**5/5. - math.cos(x*13.)/169.
fint_exact = fint(1.2)-fint(0.)
area, x, h = 0., 0., 1E-3
f0 = f1 = f2 = f(x)
while x<1.2-h*0.5:
f0,f1,f2 = f2,f(x+h),f(x+h*2.) Exact: 0.1765358676046381,
x += h*2. Numerical: 0.1765358676063498,
area += f0+f1*4.+f2
diff: 0.0000000000017117
area *= h/3.
h5 (4) L
⇡ f (x) + ... ✏approx ⇡ O(h ) ⇥ ⇡ O(h4 )
5
90 h
26
SIMPSON’S RULE:
ERROR ANALYSIS (II)
■ The total error is given
p
by:
✏m
✓ ◆
4
✏total ⇡ O( N ✏m ) + O(h ) ⇡ O p + O(h4 )
h
The best precision could be of O(10–14) when h ⇡ O(✏1/4.5
m ) ⇡ O(10 4
)
Exact = 0.1765358676046381
27
COMMENTS
■ You may already observed during our tests above, in the numeral
calculations, it is important to minimize the total error rather than
the approximation error only:
▫ Reducing the spacing h to a very small number is not a good
idea in principle; cancellation of higher order terms are more
effective.
▫ Some algorithms can reduce the spacing according to the
estimated approximation error. This is called “Adaptive
Stepping”.
▫ The key point is to use as small number of points as possible
(higher speed, less round-off error).
▫ Numerical calculations cannot be 100% precise by all means.
28
INTERMISSION
29
GETTING START WITH
NUMPY & SCIPY
FROM THE OFFICIAL WEBSITE:
In short:
NumPy = extended array + some routines
SciPy = scientific tools based on NumPy
30
TYPICAL WORK FLOW
Working on your own You can think NumPy/SciPy are nothing
research topic (TH/EXP) more than a bigger math module.
Don’t think they are something very fancy!
Problem solved!
31
NUMERICAL DERIVATIVES
IN SCIPY
■ Just google –– and you’ll find it’s just a simple function:
http://docs.scipy.org/doc/scipy/reference/generated/scipy.misc.derivative.html
32
LET’S GIVE IT A TRY
import math
import scipy.misc as misc ⇐ import scipy.misc module
def f(x):
return x**2+math.exp(x)+math.log(x)+math.sin(x)
def fp(x):
return 2.*x+math.exp(x)+1./x+math.cos(x)
x, h = 0.5, 1E-2
fp_exact = fp(x)
while h>1E-15:
fp_numeric = misc.derivative(f, x, h) ⇐ just call it
print 'h = %e' % h
print 'Exact = %.16f,' % fp_exact,
print 'Numeric = %.16f,' % fp_numeric,
print 'diff = %.16f' % abs(fp_numeric-fp_exact)
h /= 10. l7-example-04.py
33
LET’S GIVE IT A TRY (II)
■ This gives us the best precision of O(10–10) when h~10–6.
Exact = 5.5263038325905010
34
GO TO HIGHER ORDER
■ This gives us the best precision of O(10–11~10–12) when h~10–4.
Not a dramatically improvement...
x, h = 0.5, 1E-2
fp_exact = fp(x)
35
NUMERICAL INTEGRATION
WITH SCIPY
■ You’ll find there are many different integration tools in SciPy:
The quad is a general
integration tool with
QUADPACK.
Recommended!
http://docs.scipy.org/doc/scipy/reference/integrate.html#module-scipy.integrate
36
INTEGRATION WITH
QUAD() FUNCTION
import math
import scipy.integrate as integrate
def f(x):
return x - x**2 + x**3 - x**4 + math.sin(x*13.)/13.
def fint(x):
return x**2/2. - x**3/3. + x**4/4. - x**5/5. - math.cos(x*13.)/169.
fint_exact = fint(1.2)-fint(0.)
quad,quaderr = integrate.quad(f,0.,1.2,)
Exact: 0.1765358676046381
Numerical: 0.1765358676046380+-0.0000000000000029
diff: 0.0000000000000001
37
REMARK
38
HANDS-ON SESSION
■ Practice 1:
Integration rules with even higher orders can be constructed easily,
for example, comparing Simpson’s rule to 3/8 rule:
Z 2h
h 4h h
Simpson [order 2]: f (x + ⌘)d⌘ ⇡ f (x) + f (x + h) + f (x + 2h)
0 3 3 3
3/8
[order 3]:
Z 3h
3h 9h 9h 3h
f (x + ⌘)d⌘ ⇡ f (x) + f (x + h) + f (x + 2h) + f (x + 3h)
0 8 8 8 8
Try to modify l7-example-03.py to implement the 3/8 integration
rule and see how precise you can get?
39
HANDS-ON SESSION
■ Practice 2:
The integration of cosine function is sine; let’s modify the
l7-example-05.py [integration with the quad() function] code to
calculate the integration of a simple cosine and see how precise the
calculation you can get, i.e.:
def f(x):
return math.cos(x)
def fint(x):
return math.sin(x)
by integrating f(x) over the intervals of [0,!], [0,100!], [0,1000!],
[0,100.5!], [0,1000.5!]. Is it always very precise?
40