[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master d35e677 7/8: Add a unit test: root of an unfr
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master d35e677 7/8: Add a unit test: root of an unfriendly function |
Date: |
Wed, 2 Jun 2021 15:37:07 -0400 (EDT) |
branch: master
commit d35e677e779c998bf1c2b704fa79edb9e98bc6e2
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Add a unit test: root of an unfriendly function
---
zero_test.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/zero_test.cpp b/zero_test.cpp
index 23f1797..5657440 100644
--- a/zero_test.cpp
+++ b/zero_test.cpp
@@ -95,6 +95,42 @@ struct e_nineteenth
double operator()(double z) {return std::pow(z, 19);}
};
+/// A function that's unfriendly to the secant method.
+///
+/// This function is based on eq. 2.1 in Brent's fourth chapter, and
+/// is designed so that successive secant steps in Dekker's algorithm
+/// each move by only the input tolerance.
+///
+/// Following section 3 of that chapter, define
+/// k = [log2((b-a)/t)], [x] being the greatest-integer function
+/// Then bisection takes exactly k+1 iterations unless it finds a root
+/// earlier by serendipity; and the number of function evaluations
+/// required by Brent's method (counting the endpoint evaluations) is
+/// (k+1)^2 - 2 [Brent's eq. 3.4]
+///
+/// For this function, k = [log2(200/1)] = 8, so Brent's method should
+/// take no more than 9^2-2 = 79 function evaluations.
+///
+/// The parameters hardcoded here were chosen to prevent overflow.
+/// This is not a dramatic illustration of the superiority to Dekker's
+/// method, which would move by a step of 1.0 at each iteration, thus
+/// taking about 200 iterations. Brent provides an extended-exponent
+/// version for which he says the difference would be 1600 evaluations
+/// versus 1.0e12.
+
+double eq_2_1(double x)
+{
+ double a = -100.0;
+ double b = 100.0;
+ double t = 1.0; // lowercase delta = Brent's 'tol'
+ return
+ (x == a) ? -((b - a - t) / t) * std::pow(2.0, b / t)
+ : (x < a + t) ? 1.0
+ : (a + t <= x && x <= b) ? std::pow(2.0, x / t)
+ : throw "eq_2_1() out of bounds"
+ ;
+}
+
// This problem once arose in a unit test for irr calculations.
// Minimal test case:
//
@@ -200,6 +236,13 @@ int test_main(int, char*[])
test_zero(-1.0, 4.0, 0, e_19, std::exp(1.0));
test_zero(-1.0, 4.0, 100, e_19, std::exp(1.0));
+ d = brent_zero(-100.0, 100.0, 1.0e-20, eq_2_1);
+ LMI_TEST(-100.0 <= d && d <= -100.0 * (1.0 - 6.0 * epsilon));
+
+ r = decimal_root(-100.0, 100.0, bias_none, 20, eq_2_1);
+ LMI_TEST(root_is_valid == r.second);
+ LMI_TEST(-100.0 <= r.first && r.first <= -100.0 * (1.0 - 6.0 * epsilon));
+
e_former_rounding_problem e_frp;
r = decimal_root(0.12609, 0.12611, bias_lower, 5, e_frp);
#if !defined LMI_COMO_WITH_MINGW
- [lmi-commits] [lmi] master updated (f9276c0 -> f0526be), Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master ad14033 6/8: Improve and test translation from ALGOL 60, Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master f0526be 8/8: Designate release candidate 20210602T1807Z, Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master 6b65f7f 3/8: Rename certain arguments and variables, Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master e41a14f 4/8: Improve instrumentation, Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master 7a75531 2/8: Write non-const reference arguments first, Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master d0e0746 1/8: Improve documentation, Greg Chicares, 2021/06/02
- [lmi-commits] [lmi] master d35e677 7/8: Add a unit test: root of an unfriendly function,
Greg Chicares <=
- [lmi-commits] [lmi] master 9292445 5/8: Fix a unit test, Greg Chicares, 2021/06/02