Approximating function derivatives - Printable Version +- HP Forums (https://www.hpmuseum.org/forum) +-- Forum: HP Calculators (and very old HP Computers) (/forum-3.html) +--- Forum: General Forum (/forum-4.html) +--- Thread: Approximating function derivatives (/thread-21197.html) Pages: 1 2 |
Approximating function derivatives - Pekis - 01-24-2024 02:31 PM Here is a subject slightly extended from the book "La calculatrice scientifique" Vangeluwe/Glorieux, 1979: The point is to approximate function derivatives (targets are f(x0) or f'(x0) or f"(x0) or f"'(x0)) with the help of neighboring points (at distance h and h/2 from both sides of x0) So, knowing h, find a,b,c,d such as a * f(x0 + h) + b * f(x0 - h) + c * f(x0 + h/2) + d * f(x0 - h/2) ~= (f(x0) or f'(x0) or f"(x0) f"'(x0)), ie each target needs its (a,b,c,d) set In any case, with Taylor: f(x0 + h) = f(x0) + h * f'(x0) + h^2/2! * f"(x0) + h^3/3! * f"'(x0) + ... f(x0 - h) = f(x0) - h * f'(x0) + h^2/2! * f"(x0) - h^3/3! * f"'(x0) + ... f(x0 + h/2) = f(x0) + h/2 * f'(x0) + h^2/(2^2*2!) * f"(x0) + h^3/(2^3*3!) * f"'(x0) + ... f(x0 - h/2) = f(x0) - h/2 * f'(x0) + h^2/(2^2*2!) * f"(x0) - h^3/(2^3*3!) * f"'(x0) + ... => Solve system: a + b + c + d = 1 if target f(x0), else 0 a - b + c/2 - d/2 = 1/h if target f'(x0), else 0 a + b + c/4 + d/4 = 2!/(h^2) if target f"(x0), else 0 a - b + c/8 - d/8 = 3!/(h^3) if target f"'(x0), else 0 Results: If target f(x0): a = -1/6, b = -1/6, c = 2/3, d = 2/3 If target f'(x0): a = -1/(6*h), b = 1/(6*h), c = 4/(3*h), d = -4/(3*h) If target f"(x0): a = 4/(3*h^2), b = 4/(3*h^2), c = -4/(3*h^2), d = -4/(3*h^2) If target f"'(x0): a = 4/(h^3), b = -4/(h^3), c = -8/(h^3), d = 8/(h^3) Here a the results for f(x)=ln(x), h=0.001, at x0=3, from Excel: [attachment=13216] It seems nice for f(x0) and f'(x0), acceptable for f"(x0), but looses precision for f"'(x0) Did you already know that method ? RE: Approximating function derivatives - Thomas Klemm - 01-25-2024 11:38 PM (01-24-2024 02:31 PM)Pekis Wrote: Did you already know that method ? It was new to me. Thank you for sharing it with us here. I used the following Python code to print the formulas below: Code: from sympy import series, latex, symbols, Function, Matrix \( \begin{align} f{\left(- 2 h + x_{0} \right)} &= f{\left(x_{0} \right)} - 2 h \left. \frac{d}{d \xi_{1}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }} + 2 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }} - \frac{4 h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }}}{3} + O\left(h^{4}\right) \\ \\ f{\left(- h + x_{0} \right)} &= f{\left(x_{0} \right)} - h \left. \frac{d}{d \xi_{1}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }} + \frac{h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }}}{2} - \frac{h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }}}{6} + O\left(h^{4}\right) \\ \\ f{\left(h + x_{0} \right)} &= f{\left(x_{0} \right)} + h \left. \frac{d}{d \xi_{1}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }} + \frac{h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }}}{2} + \frac{h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }}}{6} + O\left(h^{4}\right) \\ \\ f{\left(2 h + x_{0} \right)} &= f{\left(x_{0} \right)} + 2 h \left. \frac{d}{d \xi_{1}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }} + 2 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }} + \frac{4 h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}} f{\left(\xi_{1} \right)} \right|_{\substack{ \xi_{1}=x_{0} }}}{3} + O\left(h^{4}\right) \\ \end{align} \) This leads to the following matrix that can be inverted: Code: M = Matrix([ \( \left[\begin{matrix} - \frac{1}{6} & \frac{2}{3} & \frac{2}{3} & - \frac{1}{6}\\ \frac{1}{12} & - \frac{2}{3} & \frac{2}{3} & - \frac{1}{12}\\ \frac{1}{3} & - \frac{1}{3} & - \frac{1}{3} & \frac{1}{3}\\ - \frac{1}{2} & 1 & -1 & \frac{1}{2} \end{matrix}\right] \) It is used in this program for the HP-42S: Code: 00 { 109-Byte Prgm } Registers R00: \(x_0\) R01: \(h\) R02: \(f(x_0 - 2h)\) R03: \(f(x_0 - h)\) R04: \(f(x_0 + h)\) R05: \(f(x_0 + 2h)\) Example 3 1E-3 XEQ "DIFF" 1.098612289 R/S 0.333333333 R/S -0.111111142 R/S 0.074074099 RE: Approximating function derivatives - Albert Chan - 01-26-2024 02:36 AM Let F(x) = f(x0 + k*h), so that F arguments are nice integers ±1, ±2 Let D = derivatives of F(x)'s, at x=0 F(1) ≈ F(0) + F'(0)*1 + F''(0)*1²/2! + F'''(0)*1³/3! --> coef = 1, 1, 1/2, 1/6 F(-1) symmetry --> coef = 1, -1, 1/2, -1/6 F(2) ≈ F(0) + F'(0)*2 + F''(0)*2²/2! + F'''(0)*2³/3! --> coef = 1, 2, 2, 4/3 F(-2) symmetry --> coef = 1, -2, 2, -4/3 Apply some symmetry before matrix inversion: Code: | 2 0 1 0 | | F(1) + F(-1) | XCas> R := inv([[2,0,1,0],[0,2,0,1/3],[2,0,4,0],[0,4,0,8/3]]) \(\left(\begin{array}{cccc} \frac{2}{3} & 0 & \frac{-1}{6} & 0 \\ 0 & \frac{2}{3} & 0 & \frac{-1}{12} \\ \frac{-1}{3} & 0 & \frac{1}{3} & 0 \\ 0 & -1 & 0 & \frac{1}{2} \end{array}\right) \) XCas> f, x0, h := ln, 3., 0.001/2 XCas> F(x) := f(x0 + x*h) XCas> X := [1, -1, 2, -2] XCas> B := map(F, X) [1.09877894145, 1.09844560811, 1.09894556646, 1.09827889977] XCas> B := [B[0]+B[1], B[0]-B[1], B[2]+B[3], B[2]-B[3]] [2.19722454956, 0.00033333333642, 2.19722446623, 0.000666666691358] XCas> D := R * B; /* = transpose(R * transpose(B) */ [1.09861228867, 0.000166666666667, -2.7777779632e-08, 9.25926002537e-12] Scale Derivatives of F(x)|x=0 to f(x)|x=x0 XCas> D / h^range(len(D)) [1.09861228867, 0.333333333333, -0.111111118528, 0.074074080203] RE: Approximating function derivatives - Paul Dale - 01-26-2024 03:29 AM The WP 34S was the first calculator I'm aware of that included a numerical derivate function (actually several flavours from memory). The very first "unexpected" issue was using the solver to find when the derivative was zero. I do not know how I never thought about this possibility. More so, since it is the completely natural outcome of supporting solve and f'. As for numeric algorithms for this, check Wikipedia. There are different solutions that depend on being one ended, two ended, etc. I must note that numeric algorithms for a function's derivative are inherent unstable. I suspect that this is the reason there has been *far* more effort put into integration (which is intractable in general). Pauli RE: Approximating function derivatives - Thomas Klemm - 01-26-2024 08:33 AM Following Albert's approach we can disentangle the calculation of odd and even derivatives. \( \begin{align} f_{+1} &= f(x_0 + h) &= f(x_0) + {f}'(x_0) h + \frac{1}{2}{f}''(x_0) h^2 + \frac{1}{6}{f}'''(x_0) h^3 + \mathcal{O}(h^4) \\ \\ f_{-1} &= f(x_0 - h) &= f(x_0) - {f}'(x_0) h + \frac{1}{2}{f}''(x_0) h^2 - \frac{1}{6}{f}'''(x_0) h^3 + \mathcal{O}(h^4) \\ \\ f_{+2} &= f(x_0 + 2h) &= f(x_0) + 2{f}'(x_0) h + 2{f}''(x_0) h^2 + \frac{4}{3}{f}'''(x_0) h^3 + \mathcal{O}(h^4) \\ \\ f_{-2} &= f(x_0 - 2h) &= f(x_0) - 2{f}'(x_0) h + 2{f}''(x_0) h^2 - \frac{4}{3}{f}'''(x_0) h^3 + \mathcal{O}(h^4) \\ \\ \end{align} \) Even derivatives \( \begin{align} f_{+1} + f_{-1} &= 2f(x_0) + {f}''(x_0) h^2 + \mathcal{O}(h^4) \\ f_{+2} + f_{-2} &= 2f(x_0) + 4{f}''(x_0) h^2 + \mathcal{O}(h^4) \\ \end{align} \) Or: \( \begin{bmatrix} f_{+1} + f_{-1} \\ f_{+2} + f_{-2} \\ \end{bmatrix} \approx \begin{bmatrix} 2 & 1 \\ 2 & 4 \\ \end{bmatrix} \cdot \begin{bmatrix} f(x_0) \\ {f}''(x_0) h^2 \\ \end{bmatrix} \) This leads to: \( \begin{bmatrix} f(x_0) \\ {f}''(x_0) h^2 \\ \end{bmatrix} \approx \begin{bmatrix} \frac{2}{3} & - \frac{1}{6} \\ - \frac{1}{3} & \frac{1}{3} \\ \end{bmatrix} \cdot \begin{bmatrix} f_{+1} + f_{-1} \\ f_{+2} + f_{-2} \\ \end{bmatrix} \) Odd derivatives \( \begin{align} f_{+1} - f_{-1} &= 2{f}'(x_0) h + \frac{1}{3}{f}'''(x_0) h^3 + \mathcal{O}(h^4) \\ f_{+2} - f_{-2} &= 4{f}'(x_0) h + \frac{8}{3}{f}'''(x_0) h^3 + \mathcal{O}(h^4) \\ \end{align} \) Or: \( \begin{bmatrix} f_{+1} - f_{-1} \\ f_{+2} - f_{-2} \\ \end{bmatrix} \approx \begin{bmatrix} 2 & \frac{1}{3} \\ 4 & \frac{8}{3} \\ \end{bmatrix} \cdot \begin{bmatrix} {f}'(x_0) h \\ {f}'''(x_0) h^3 \\ \end{bmatrix} \) This leads to: \( \begin{bmatrix} {f}'(x_0) h \\ {f}'''(x_0) h^3 \\ \end{bmatrix} \approx \begin{bmatrix} \frac{2}{3} & - \frac{1}{12} \\ - 1 & \frac{1}{2} \\ \end{bmatrix} \cdot \begin{bmatrix} f_{+1} - f_{-1} \\ f_{+2} - f_{-2} \\ \end{bmatrix} \) This allows to optimise the program for the HP-42S a bit: Code: 00 { 103-Byte Prgm } Registers R00: \(x_0\) R01: \(h\) R02: \(f_{+1} + f_{-1}\) R03: \(f_{+1} - f_{-1}\) R04: \(f_{+2} + f_{-2}\) R05: \(f_{+2} - f_{-2}\) RE: Approximating function derivatives - Albert Chan - 01-26-2024 01:32 PM (01-24-2024 02:31 PM)Pekis Wrote: It seems nice for f(x0) and f'(x0), acceptable for f"(x0), but looses precision for f"'(x0) f(x0+h) = f(x0) + f'(x0)*h + f''(x0)*h²/2! + f'''(x0)*h³/2! + O(h4) if we fit points f(x0±h), f(x0±2h), and estimate f(x0), error = O(h4) Rewrite same taylor series, horner style f(x0+h) = f(x0) + h*( f'(x0) + h/2*( f''(x0) + h/3*( f'''(x0) + O(h) ))) Estimated f'''(x0) has error = O(h), much worse. (01-26-2024 08:33 AM)Thomas Klemm Wrote: Even derivatives Let f±k = fk + f-k, where fk = f(x0 + k*h) Ignore O(h^4), solve for f''(x0), we have: \(\displaystyle {f}''(x_0) ≈ \left(-\frac{1}{3}f_{±1} + \frac{1}{3}f_{±2}\right) /\,h^2 \) If we have the missing gap, (x0, f(x0)), f''(x0) can be estimated slightly better. \( \begin{align} (f_{±1} - 2 f_{0}) &= {f}''(x_0)\; h^2 + \mathcal{O}(h^4) \\ (f_{±2} - 2 f_{0}) &= {f}''(x_0)\; (2h)^2 + \mathcal{O}((2h)^4) \\ \end{align} \) Instead of ignore error terms, this time we cancel them: \( 16×(f_{±1} - 2 f_0) - (f_{±2} - 2 f_0) ≈ {f}''(x_0)\; h^2 × (16 - 4) \) \(\displaystyle {f}''(x_0) ≈ \left(-\frac{5}{2}f_0 + \frac{4}{3}f_{±1} - \frac{1}{12}f_{±2}\right) /\,h^2 \) RE: Approximating function derivatives - Albert Chan - 01-26-2024 09:51 PM (01-26-2024 01:32 PM)Albert Chan Wrote: Let f±k = fk + f-k, where fk = f(x0 + k*h) If h is tiny, above setup may cause massive cancellations. It is better to write formula using finite difference operators. Bonus: it explained why denominator is 1 - (-2) = 3 \(\displaystyle D^2\;h^2 ≈ \frac{Δ_{1} - Δ_{-2}}{3}\) lua> x0, h = 3, 0.001/2 lua> f = setmetatable({}, {__index = fn'T,k: rawset(T,k,log(x0+k*h))[k]'}) -- memoize lua> ((f[2]-f[1]) - (f[-1]-f[-2])) / (3*h^2) -0.11111111912024776 Quote:If we have the missing gap, (x0, f(x0)), f''(x0) can be estimated slightly better. We can use Divided difference (both sides) to estimate derivatives One-sided also work, but have error of O(h) instead of O(h^2) \(\displaystyle \underset{^h}{⍋}^p = D^{\,p} + \mathcal{O}(h^2) \) Then, apply Richardson extrapolation to improve estimate. \(\displaystyle D^{\,p} ≈ \underset{^h}{⍋}^p + (\underset{^h}{⍋}^p - \underset{^{2h}}{⍋}^p)/3 \) 1st derivatives, set p=1 lua> d1 = (f[1]-f[-1]) / (2*h) lua> d2 = (f[2]-f[-2]) / (4*h) lua> d1, d2 0.33333333641971663 0.33333334567897666 lua> d1 + (d1-d2)/3 0.3333333333332966 2nd derivatives, set p=2 lua> d1 = ((f[1]-f[0]) - (f[0]-f[-1])) / (h^2) lua> d2 = ((f[2]-f[0]) - (f[0]-f[-2])) / (4*h^2) lua> d1, d2 -0.11111111319905831 -0.11111111763995041 lua> d1 + (d1-d2)/3 -0.11111111171876094 RE: Approximating function derivatives - Pekis - 01-27-2024 08:04 AM I've found a more iterative way, and it seems interesting: f'(x0) ~= a * f(x0-2h) + b * f(x0-h) + c * f(x0+h) + d * f(x0+2h): => a = 1/(12h), b = -8/(12h), c = 8/(12h), d = -1/(12h) But after all, if the first derivative f'(x0) ~= a * f(x0-2h) + b * f(x0-h) + c * f(x0+h) + d * f(x0+2h) (already very good precision), then the 2nd derivative f"(x0) ~= a * f'(x0-2h) + b * f'(x0-h) + c * f'(x0+h) + d * f'(x0+2h) will have good precision, and so on, with the same a, b, c, d coefficients from above: So, if you want it, f"(x0) ~= a * f'(x0-2h) + b * f'(x0-h) + c * f'(x0+h) + d * f'(x0+2h): the f'(x0-2h) term has to be calculated as a * f(x0-4h) + b * f(x0-3h) + c * f(x0-h) + d * f(x0) (since f'(x0) ~= a * f(x0-2h) + b * f(x0-h) + c * f(x0+h) + d * f(x0+2h)) the f'(x0-h) term has to be calculated as a * f(x0-3h) + b * f(x0-2h) + c * f(x0) + d * f(x0+h) the f'(x0+h) term has to be calculated as a * f(x0-h) + b * f(x0) + c * f(x0+2h) + d * f(x0+3h) the f'(x0+2h) term has to be calculated as a * f(x0) + b * f(x0+h) + c * f(x0+3h) + d * f(x0+4h) We can reuse previous calculations but also have to add new ones: f(x0-4h), f(x0-3h), f(x0+3h), f(x0+4h). And if you want it, f3(x0) ~= a * f"(x0-2h) + b * f"(x0-h) + c * f"(x0+h) + d * f"(x0+2h): the f"(x0-2h) term has to be calculated as a * f'(x0-4h) + b * f'(x0-3h) + c * f'(x0-h) + d * f'(x0) the f"(x0-h) term has to be calculated as a * f'(x0-3h) + b * f'(x0-2h) + c * f'(x0) + d * f'(x0+h) the f"(x0+h) term has to be calculated as a * f'(x0-h) + b * f'(x0) + c * f'(x0+2h) + d * f'(x0+3h) the f"(x0+2h) term has to be calculated as a * f'(x0) + b * f'(x0+h) + c * f'(x0+3h) + d * f('x0+4h) So, we can reuse previous calculations but also have to add new ones: f'(x0-4h) = a * f(x0-6h) + b * f(x0-5h) + c * f(x0-3h) + d * f(x0-2h) f'(x0-3h) = a * f(x0-5h) + b * f(x0-4h) + c * f(x0-2h) + d * f(x0-h) f'(x0+3h) = a * f(x0+h) + b * f(x0+2h) + c * f(x0+4h) + d * f(x0+5h) f'(x0+4h) = a * f(x0+2h) + b * f(x0+3h) + c * f(x0+5h) + d * f(x0+6h) We can reuse previous calculations but also have to add new ones: f(x0-6h), f(x0-5h), f(x0+5h), f(x0+6h). The precision seems good, as shown in the Excel attachment here, which also shows the building tree: [attachment=13232] What do you think of it ? RE: Approximating function derivatives - Albert Chan - 01-27-2024 03:34 PM Hi, Pekis Yes, your way work! I think you just re-discovered divided finite-difference (see post #7) Think of divided finite-difference as slope. slope of slope is 2nd derivatives. slope of 2nd gives 3rd ... That's why you get Excel table with triangular shape. RE: Approximating function derivatives - Pekis - 01-27-2024 03:46 PM Thanks Albert for your lights, and as we say in French, "Tous les chemins mènent à Rome" ?. It was fun RE: Approximating function derivatives - Namir - 01-28-2024 12:55 AM Interesting subject! Whenever I calculate the root (or optimum) for a single-variable equation, I approximate the first derivative (and sometimes the second derivative, depending on the algorithm). This means that the approximations to the derivatives translate into function calls. I usually keep track of the total number of function calls needed by the algorithm to obtain a satisfactory approximation to the root (or optimum). I regard the number of function calls as a measure of the efficiency of the algorithms. Many new root-seeking algorithms that have come out in the last two decades use iterations where the guess to the root is refined multiple times in each iteration, and thus require several function calls. These new root-seeking algorithms claim orders of convergence that are higher than those of Newton or Halley. They also claim fewer iterations. But when it comes to the total number of function calls, these new algorithms exceed the total number of function calls needed by legacy root-seeking methods. I doubt that 4 function calls to calculate the first derivative (plus another one to call f(x)) will greatly reduce the number of iterations compared to 2 functions used by Newton's method. My bet is that the reduction will be by 1, or at most 2 iterations (maybe???) compared to Newton's method. Code:
RE: Approximating function derivatives - Albert Chan - 01-28-2024 01:37 AM Hi, Namir You could still do 2 function calls per Newton step, yet getting much better correction! \(\displaystyle \frac{f(x)}{f'(x)} = \frac {\frac{f(x+h) + f(x-h)}{2} + \mathcal{O}(h^2)} {\frac{f(x+h) - f(x-h)}{2h} + \mathcal{O}(h^2)} ≈ \frac{f(x+h) + f(x-h)}{f(x+h) - f(x-h)} ×h \) see thread (HP71B) Newton's method RE: Approximating function derivatives - Thomas Klemm - 01-28-2024 01:32 PM These programs are written for the HP-42S but were executed on Free42. Namir Code: 00 { 52-Byte Prgm } Example 5 ENTER 1E-3 XEQ "NAMIR" R/S … 2.304147465437788018433179723502304 0.770582759117462734739653197597686 1.111023035061702437701327055382557e-1 2.428155751994818176546315444651607e-3 1.624379123244663423625637280518858e-6 3.174993748595121727106213314729139e-10 6.195745943475227358884079854367656e-14 1.209049801358665977248358523936021e-17 2.359363078168320091909037111452332e-21 4.604106574179830863422014948995832e-25 8.984529451135328979667386689678538e-29 1.756277341070306049325741843354146e-32 0 Albert Code: 00 { 59-Byte Prgm } Example 5 ENTER 1E-3 XEQ "ALBERT" R/S … 2.304347913043478260869565217391304 7.705390983101360703696388627092945e-1 1.109729765704264257764977158661139e-1 2.401390226528627812090476848659566e-3 1.125539305782882856562088581234399e-6 2.472616204210897690330978112713164e-13 1.193297714696925294598932151109756e-26 4.87950073651416474628973288871039e-34 4.87950073651416474628973288871039e-34 … Newton Code: 00 { 51-Byte Prgm } 5 XEQ "NEWTON" R/S … 2.304347826086956521739130434782609 7.705390207104649567960499245645317e-1 1.109729473922707134927056532859122e-1 2.401388782294756614038691927472916e-3 1.125537866194583738614244483824163e-6 2.472609690769991318136999747343159e-13 1.193291280428526545827413545935046e-26 0 Conclusion Both ALBERT and NEWTON provide quadratic convergence while NAMIR only provides linear convergence. ALBERT may not end up with \(f(x) = 0\) as this is never evaluated. All programs use two function evaluations per iteration. For NEWTON an implementation of \({f}'(x)\) has to be provided. RE: Approximating function derivatives - Thomas Klemm - 01-28-2024 01:42 PM (09-07-2018 11:32 AM)Massimo Gnerucci Wrote: (01-28-2024 12:55 AM)Namir Wrote: I regard the number of function calls as a measure of the efficiency of the algorithms. Albert shows us that we can have our cake and eat it too. RE: Approximating function derivatives - Namir - 01-29-2024 01:46 AM (01-28-2024 01:37 AM)Albert Chan Wrote: Hi, Namir I found your approach interesting. I tested it with f(x)=exp(x)-3*x^2 an used two versions of Newton's and Halley's methods--one using calculated f(x) and one approximating f(x) with f(x+h) and f(x-h). I came to the conclusion that your approach attempts to find the root of some (f(x+h)-f(x-h))/2 and NOT f(x) itself. Your approach works only if f(x) represents a straight line. The results of your averaging f(x) yields roots with fewer accurate decimals. Namir RE: Approximating function derivatives - Paul Dale - 01-29-2024 02:59 AM Everyone needs to remember that numerical derivative algorithms are generally very unstable. Personally, I'd follow the literature (which is generally very well researched). Pauli RE: Approximating function derivatives - Albert Chan - 01-29-2024 12:59 PM (01-29-2024 01:46 AM)Namir Wrote: I found your approach interesting. I tested it with f(x)=exp(x)-3*x^2 an used two versions of Newton's and Halley's methods--one using calculated f(x) and one approximating f(x) with f(x+h) and f(x-h). I came to the conclusion that your approach attempts to find the root of some (f(x+h)-f(x-h))/2 and NOT f(x) itself. Your approach works only if f(x) represents a straight line. The results of your averaging f(x) yields roots with fewer accurate decimals. FYI, this is *exactly* secant's method, from 2 points: (x1,y1), (x2,y2) = ((x-h), f(x-h)), ((x+h), f(x+h)) We assume f from x1 to x2 is a striaght line. (only a tiny section, not the full f(x)) Thus, it make no difference how we pick for 1 or 2. Both get the same secant root. x' = x1 - y1 * (x1-x2)/(y1-y2) x' = x2 - y2 * (x1-x2)/(y1-y2) Take the mean of these equivalent formula: x' = (x1+x2)/2 - (y1+y2)/2 * (x1-x2)/(y1-y2) = x - (y1+y2)/(y1-y2) * h Newton correction dx = f(x)/f'(x) ≈ (y1+y2)/(y1-y2) * h If |dx| bigger than h (i.e. extrapolation), then correction estimate is good. If |dx| smaller than h, we get into interpolation (note: f(x) never evaluated) (x-h) ---- (x') -- (x) ------------ (x+h) Whole section assumed straight line, interpolation to x' is not good, but closer. With 1 function call, we can correct for this with another Newton step: x'' = x' - f(x') / f'(x') ≈ x' - f(x') / (slope used to get from x to x') We can of course set h small enough, so that x' is acceptable, skipping x'' RE: Approximating function derivatives - Albert Chan - 01-29-2024 01:02 PM Instead of fixed h, we can based from a fraction of previous dx. Code: function S.newton(f,x,h0,eps,verbal) lua> S = require'solver' lua> f = fn'x:exp(x) - 3*x^2' lua> S.newton(f, -1, 1e-3, 1e-9, true) -1 -0.5866562214529973 -0.4698017256933633 -0.45905390325056966 -0.4589622741012877 -0.4589622675369419 -0.4589622675369485 12 lua> f(_) -1.1102230246251565e-16 lua> S.newton(f, 1, 1e-3, 1e-9, true) 1 0.914154769981483 0.9100176589772936 0.9100075725386966 0.910007572488709 9 lua> f(_) 0 RE: Approximating function derivatives - Namir - 01-29-2024 01:25 PM I used an initial guess of 6 for exp(x)-3*x^2 and 1e-16 as the tolerance for x. I also made another code version where the tolerance is applied to abs(f(x)). Here is the Excel VBA code that I used to test for convergence of the guess refinment: Code: Option Explicit Here is the output with calculated fx(x): Code:
Here is the output with approximated value of fx(x): Code:
The second set shows reduced accuracy in the refined guess for the root. Here is the Excel VBA code that I used to test the abs(fx(x)): Code: Option Explicit Again, the results I get tell me that approximating f(x) with (f(x+h)+f(x+h))/2 reduces the accuracy of the result. We can use any version that fit our conviction. RE: Approximating function derivatives - Albert Chan - 01-29-2024 02:27 PM (01-29-2024 01:25 PM)Namir Wrote: I used an initial guess of 6 for exp(x)-3*x^2 and 1e-16 as the tolerance for x. Ah, I missed the big root. Since I expected quadratic convergence, I set eps = 1e-9, initial h = 1e-3 Again, h is decreasing along with dx, not a fixed number. lua> S = require'solver' lua> f = fn'x:exp(x) - 3*x^2' lua> S.newton(f, 6, 1e-3, 1e-9, true) 6 5.195955942003588 4.52948873087134 4.053975908526381 3.80408413181784 3.737403183742807 3.7330961934908533 3.7330790288874782 3.7330790286328144 17 lua> f(_) 7.105427357601002e-15 This is very similar to true Newton's method lua> df = fn'x:exp(x) - 6*x' lua> x = 6 lua> for i=1,9 do print(x); x = x-f(x)/df(x) end 6 5.195956335690451 4.529489328402691 4.053976528531787 3.8040845309684834 3.7374032842820784 3.733096198370094 3.733079028904745 3.7330790286328144 |