summaryrefslogtreecommitdiff
path: root/src/roots.c
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2023-11-11 13:15:59 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2023-11-11 13:15:59 -0700
commit3f1f18b149788fe69180dc2a348fd32425bb9a3f (patch)
tree582e7b773f16e54c7e4ca71de902d65316900767 /src/roots.c
parent586d8056c1c9e4bb4b8ef219babadc997559b83d (diff)
downloadcmath-3f1f18b149788fe69180dc2a348fd32425bb9a3f.tar.gz
cmath-3f1f18b149788fe69180dc2a348fd32425bb9a3f.zip
hw6
Diffstat (limited to 'src/roots.c')
-rw-r--r--src/roots.c111
1 files changed, 96 insertions, 15 deletions
diff --git a/src/roots.c b/src/roots.c
index de16adf..d6b22af 100644
--- a/src/roots.c
+++ b/src/roots.c
@@ -3,34 +3,35 @@
#include <math.h>
// f is well defined at start_x + delta*n for all n on the integer range [0,
-// max_steps]
-double *find_ivt_range(double (*f)(double), double start_x, double delta,
- size_t max_steps) {
- double *range = malloc(sizeof(double) * 2);
-
+// max_iterations]
+Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
+ size_t max_iterations) {
double a = start_x;
- while (f(a) * f(start_x) >= 0 && max_steps-- > 0)
+ while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
+ max_iterations--;
a += delta;
+ }
- if (max_steps == 0 && f(a) * f(start_x) > 0)
- return NULL;
+ double end = a + delta;
+ double begin = a - delta;
- range[0] = start_x;
- range[1] = a + delta;
- return range;
+ if (max_iterations == 0 && f(begin) * f(end) >= 0)
+ return NULL;
+ return InitArray(double, {begin, end});
}
// f is continuous on [a, b]
-double bisect_find_root(double (*f)(double), double a, double b,
- double tolerance, size_t max_iterations) {
+Array_double *bisect_find_root(double (*f)(double), double a, double b,
+ double tolerance, size_t max_iterations) {
assert(a <= b);
// guarantee there's a root somewhere between a and b by IVT
assert(f(a) * f(b) < 0);
double c = (1.0 / 2) * (a + b);
if (b - a < tolerance || max_iterations == 0)
- return c;
+ return InitArray(double, {a, b, c});
+
if (f(a) * f(c) < 0)
return bisect_find_root(f, a, c, tolerance, max_iterations - 1);
return bisect_find_root(f, c, b, tolerance, max_iterations - 1);
@@ -42,5 +43,85 @@ double bisect_find_root_with_error_assumption(double (*f)(double), double a,
uint64_t max_iterations =
(uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0));
- return bisect_find_root(f, a, b, tolerance, max_iterations);
+
+ Array_double *a_b_root = bisect_find_root(f, a, b, tolerance, max_iterations);
+ double root = a_b_root->data[2];
+ free_vector(a_b_root);
+
+ return root;
+}
+
+double fixed_point_iteration_method(double (*f)(double), double (*g)(double),
+ double x_0, double tolerance,
+ size_t max_iterations) {
+ if (max_iterations <= 0)
+ return x_0;
+
+ double root = g(x_0);
+ if (tolerance >= fabs(f(root)))
+ return root;
+
+ return fixed_point_iteration_method(f, g, root, tolerance,
+ max_iterations - 1);
+}
+
+double fixed_point_newton_method(double (*f)(double), double (*fprime)(double),
+ double x_0, double tolerance,
+ size_t max_iterations) {
+ if (max_iterations <= 0)
+ return x_0;
+
+ double root = x_0 - f(x_0) / fprime(x_0);
+ if (tolerance >= fabs(f(root)))
+ return root;
+
+ return fixed_point_newton_method(f, fprime, root, tolerance,
+ max_iterations - 1);
+}
+
+double fixed_point_secant_method(double (*f)(double), double x_0, double x_1,
+ double tolerance, size_t max_iterations) {
+ if (max_iterations == 0)
+ return x_1;
+
+ double root = x_1 - f(x_1) * ((x_1 - x_0) / (f(x_1) - f(x_0)));
+
+ if (tolerance >= fabs(f(root)))
+ return root;
+
+ return fixed_point_secant_method(f, x_1, root, tolerance, max_iterations - 1);
+}
+
+double fixed_point_secant_bisection_method(double (*f)(double), double x_0,
+ double x_1, double tolerance,
+ size_t max_iterations) {
+ double begin = x_0;
+ double end = x_1;
+ double root = x_0;
+
+ while (tolerance < fabs(f(root)) && max_iterations > 0) {
+ max_iterations--;
+
+ double secant_root = fixed_point_secant_method(f, begin, end, tolerance, 1);
+
+ if (secant_root < begin || secant_root > end) {
+ Array_double *range_root = bisect_find_root(f, begin, end, tolerance, 1);
+
+ begin = range_root->data[0];
+ end = range_root->data[1];
+ root = range_root->data[2];
+
+ free_vector(range_root);
+ continue;
+ }
+
+ root = secant_root;
+
+ if (f(root) * f(begin) < 0)
+ end = secant_root; // the root exists in [begin, secant_root]
+ else
+ begin = secant_root;
+ }
+
+ return root;
}