Source code for numa.RootFinder._regulaFalsi
from numa import utils
[docs]def regulaFalsi(function, interval_start, interval_end, max_iterations=10000, giveIterations=False):
"""Approximate one root of a given one-parameter function using the Regula Falsi method;
note that the root has to be inside the interval or the method won't yield any results.
This method can only return one of the possible roots if multiple exist and is generally not used due to it's
unstable nature.
Parameters
----------
function: callable
Function to analyze.
interval_start: int
lower limit of the domain
interval_end: int
upper limit of the domain
max_iterations: int
Maximum number of iterations until the loop breaks. Default set to 10000
giveIterations: boolean, optional
Information whether the value for iterations needed and the error should be returned or not. Lists starts at iteration two
since the error is always calculated with respect to the previous guess.
Returns
-------
tuple
(root value, error, convergence)
Notes
-----
Calculates the next upper limit for the interval as
.. math::
x_k = \\frac{af(b) - bf(a)}{f(b)-f(a)} \\Longrightarrow [a_n, x_k] \\quad \\text{or} \\quad [x_k, b_n]
but chooses the next interval based on the position of x_k.
"""
err_accepted = 10e-15
a_n = interval_start
b_n = interval_end
convergence = list()
for n in range(1, max_iterations + 1):
x_k = _calcX_k(function, a_n, b_n) # Crossing point
y_n = function(x_k) # Function value at crossing point
if function(a_n) * y_n < 0: # root is on left side of x_k
b_n = x_k # set new interval end
err = abs(function(x_k) - 0)
convergence.append((n, err))
if err < err_accepted:
if not giveIterations:
return _calcX_k(function, a_n, b_n), err
if giveIterations:
return _calcX_k(function, a_n, b_n), err, convergence
elif function(b_n) * y_n < 0: # root is on right side of x_k
a_n = x_k # set new interval start
err = abs(function(x_k) - 0)
convergence.append((n, err))
if err < err_accepted:
if not giveIterations:
return _calcX_k(function, a_n, b_n), err
if giveIterations:
return _calcX_k(function, a_n, b_n), err, convergence
elif y_n == 0: # Exact solution
if not giveIterations:
return x_k, 0
if giveIterations:
convergence.append((n, 0))
return x_k, 0, convergence
else:
utils.MethodStuckError(
"Regula Falsi won't converge to root. Please adjust limits."
)
raise utils.MaximumIterationError(n)
def _calcX_k(function, a_n, b_n):
return (a_n * function(b_n) - b_n * function(a_n)) / (function(b_n) - function(a_n))