 ---
 # With great growth come great errors
 ---


```python
import numpy as np
np.version.version
```




    '1.14.3'



Lets compute derivate based on the stencil method [link](http://web.media.mit.edu/~crtaylor/calculator.html)
I have chosen locations of sampled points equal to 0,1,2,3,4,5 since I do not want use negative locations with limited data.


```python
def df_1(f,h):
    f = np.float64(f)
    h = np.float64(h)
    df = lambda f, h:((-137*f[0]+300*f[1]-300*f[2]+200*f[3]-75*f[4]+12*f[5])/(60*1.0*h))
    return [df(f[j:j+6], 1) for j in range(0,f.size-6)]
```

Lets take strongly monotonicly growing function:


```python
TestFun  = np.asarray([np.power(2,x)+1 for x in range(50)])
```

We know that we know that f is monotonicly growing function, so we can present it as $f(x)=e^{g(x)}$, if we differentiate it we will get:

$\frac{d}{dx}f(x)=\frac{d}{dx}(e^{g(x)})=e^{g(x)}\frac{d}{dx}g(x)$ so:

\begin{equation}\tag{1} \frac{d}{dx}g(x) = \frac{\frac{d}{dx}f(x)}{f(x)}\end{equation}
<a id='chain_identity'></a>


```python
def d_g(f,h):
    df1 = df_1(f,h)
    return [(df1[j]/f[j]) for j in range(0,f.size-6)]

dg1 = d_g(TestFun,100)
np.transpose(dg1)
```




    array([0.39166667, 0.52222222, 0.62666667, 0.6962963 , 0.7372549 ,
           0.75959596, 0.77128205, 0.77726098, 0.78028534, 0.78180637,
           0.78256911, 0.78295103, 0.78314214, 0.78323772, 0.78328553,
           0.78330943, 0.78332138, 0.78332736, 0.78333035, 0.78333184,
           0.78333259, 0.78333296, 0.78333315, 0.78333324, 0.78333329,
           0.78333331, 0.78333332, 0.78333333, 0.78333333, 0.78333333,
           0.78333333, 0.78333333, 0.78333333, 0.78333333, 0.78333333,
           0.78333333, 0.78333333, 0.78333333, 0.78333333, 0.78333333,
           0.78333333, 0.78333333, 0.78333333, 0.78333333])



But since $f(x)=e^{g(x)}$ then we also know that: 
\begin{equation}\nonumber\ln(f(x))=\ln(e^{g(x)})=g(x)\end{equation} so:
\begin{equation}\tag{2}\frac{d}{dx}\ln(f(x))=\frac{d}{dx}(\ln(e^{g(x)}))=\frac{d}{dx}g(x)\end{equation}
<a id='log_identity'></a>


```python
def d_ln(f,h):
    return df_1(np.log(f),h)

dg2 = d_ln(TestFun,100)
np.transpose(dg2)
```




    array([0.34505258, 0.4608561 , 0.55417653, 0.61620674, 0.65251573,
           0.67224712, 0.68254505, 0.6878073 , 0.69046744, 0.69180484,
           0.6924754 , 0.69281113, 0.69297912, 0.69306314, 0.69310516,
           0.69312617, 0.69313667, 0.69314193, 0.69314455, 0.69314587,
           0.69314652, 0.69314685, 0.69314702, 0.6931471 , 0.69314714,
           0.69314716, 0.69314717, 0.69314718, 0.69314718, 0.69314718,
           0.69314718, 0.69314718, 0.69314718, 0.69314718, 0.69314718,
           0.69314718, 0.69314718, 0.69314718, 0.69314718, 0.69314718,
           0.69314718, 0.69314718, 0.69314718, 0.69314718])



since [(1)](#chain_identity) and [(2)](#log_identity) we get:

\begin{equation}\nonumber\frac{d}{dx}\ln(f(x))=\frac{\frac{d}{dx}f(x)}{f(x)}\end{equation}   


```python
np.subtract(dg1,dg2)
```




    array([0.04661409, 0.06136612, 0.07249014, 0.08008956, 0.08473917,
           0.08734884, 0.088737  , 0.08945368, 0.08981791, 0.09000152,
           0.09009371, 0.0901399 , 0.09016302, 0.09017458, 0.09018037,
           0.09018326, 0.09018471, 0.09018543, 0.09018579, 0.09018597,
           0.09018606, 0.09018611, 0.09018613, 0.09018614, 0.09018615,
           0.09018615, 0.09018615, 0.09018615, 0.09018615, 0.09018615,
           0.09018615, 0.09018615, 0.09018615, 0.09018615, 0.09018615,
           0.09018615, 0.09018615, 0.09018615, 0.09018615, 0.09018615,
           0.09018615, 0.09018615, 0.09018615, 0.09018615])



Not true, there is significant difference. Lets check which solution is closer to the truth.

\begin{equation}\nonumber \frac{d}{dx}g(x) = \frac{d}{dx}(\log(2^x + 1)) \end{equation}


```python
from sympy import *
x = symbols('x')
init_printing(use_latex='mathjax')
diff(log(pow(2,x)+1), x)
```




$$\frac{2^{x} \log{\left (2 \right )}}{2^{x} + 1}$$



\begin{equation}\nonumber \frac{d}{dx}g(x) = \frac{2^x \log(2)}{2^x + 1}\end{equation}


```python
def d_direct():
    f_size = 50
    return np.asarray([(np.power(2,x)*np.log(2)/(np.power(2,x)+1)) for x in range(0,f_size-6)])
dg3 = d_direct()
np.transpose(dg3)
```




    array([0.34657359, 0.46209812, 0.55451774, 0.61613083, 0.65237382,
           0.67214272, 0.68248338, 0.68777395, 0.69045011, 0.69179602,
           0.69247094, 0.69280889, 0.692978  , 0.69306258, 0.69310488,
           0.69312603, 0.6931366 , 0.69314189, 0.69314454, 0.69314586,
           0.69314652, 0.69314685, 0.69314702, 0.6931471 , 0.69314714,
           0.69314716, 0.69314717, 0.69314718, 0.69314718, 0.69314718,
           0.69314718, 0.69314718, 0.69314718, 0.69314718, 0.69314718,
           0.69314718, 0.69314718, 0.69314718, 0.69314718, 0.69314718,
           0.69314718, 0.69314718, 0.69314718, 0.69314718])




```python
np.linalg.norm(np.subtract(dg3,dg2))
```




$$0.00200365957032477$$



When you play with exponentially growing functions, be careful with calculus. In general:

From rules of [uncertanity propagation](https://en.wikipedia.org/wiki/Propagation_of_uncertainty) we can take:

\begin{equation} f(x) = a\cdot e^{b\cdot g(x)}  \implies  \sigma_{f(x)} \approx \lvert f(x)\cdot b\cdot\sigma_{g(x)}\rvert\end{equation}

Which means the $\sigma_{f(x)}$ grows with growing $f(x)$ even if $\sigma_{g(x)}$ stabilizes at some point.

 

### Conclusion: 
### [With great power comes great responsibility.](https://en.wikipedia.org/wiki/Uncle_Ben) [With great growth come great errors.](https://flmath.github.io/subpages/cv/my_cv.html) 

5ea31d936986dbca05328eb26bb8ac30cee34bb2
ipynb
Jupyter Notebook
Numerical_error__derivations_and_exponential_functions.ipynb
flmath/numerical-errors
ecfe6fb8d198a18a900144c91d86bb5737f4ad1d
Apache-2.0
Numerical_error__derivations_and_exponential_functions.ipynb
flmath/numerical-errors
ecfe6fb8d198a18a900144c91d86bb5737f4ad1d
Apache-2.0
Numerical_error__derivations_and_exponential_functions.ipynb
flmath/numerical-errors
ecfe6fb8d198a18a900144c91d86bb5737f4ad1d
Apache-2.0
Qwen/Qwen-72B
1. YES
2. YES