I'm attempting a bit of code that would help me approximate the derivatives of an arbitrary function. I saw there were four options on another post:
- Finite Differences
- Automatic Derivatives
- Symbolic Differentiation
- Compute derivatives by hand
I saw that my approach falls best in the first option, which had the note, "prone to numerical error". So I'm aware that this method isn't expected to be exact, which is fine.
That being said, I did some research into what size numbers can be stored by different data types, and found in this post that it can be quite small, (on the order of 10–308) and that "In the normal range, results of elementary operations will be accurate within the normal precision of the format".
That being said, I seem to be getting extremely bad outcomes for this following code snippet where I explore different sized intervals; the smallest difference shouldn't be much smaller than 10–27 (10–9, cubed), which is much larger than the limiting value. I would appreciate maybe a more specific response?
epsilon = 0.01 # is "small" w.r.t. to 3
def approx_derivative(func): # rough derivative factory function
return lambda x : (func(x + epsilon) - func(x)) / epsilon
while epsilon > 10**-9:
nth_deriv = lambda x : x ** 3 # 0th derivative
for i in range(5): # should read about 27, 27, 18, 6, 0
print(nth_deriv(3), end=', ')
nth_deriv = approx_derivative(nth_deriv) # take derivative
print('\n')
epsilon *= 0.1
The output is:
27, 27.090099999999495, 18.0599999999842, 6.000000002615025, -3.552713678800501e-07,
27, 27.009000999996147, 18.00600000123609, 6.000000496442226, -0.007105427357601002,
27, 27.00090001006572, 18.000599766310188, 6.004086117172847, -71.05427357601002,
27, 27.000090000228735, 18.000072543600254, 3.5527136788005005, 355271.36788005003,
27, 27.000009005462285, 17.998047496803334, 0.0, 3552713678.8005,
27, 27.000000848431675, 18.11883976188255, 0.0, -35527136788004.99,
27, 27.0000001023618, 0.0, 0.0, 3.552713678800497e+17,
27, 27.000002233990003, 0.0, 0.0, 0.0,
As we can see in the first couple of examples, the results aren't exact but are pretty good. For certain interval sizes, though, some values are blown up; others go to 0; and some are just plain wrong, like giving half the value, despite the intuition that they should become more accurate for smaller epsilons. What main things can I attribute to this error? What should I be looking out for/be cautious of? Are there errors I should be worried about catching with a block (like division by 0)?
Is there a value for epsilon that is generally considered "best" for doing computations with floats? Or is there a "rule-of-thumb" for choosing a good-sized epsilon based on your input? Is there a preferred definition of the derivative to use over the one I implemented?