6#include <isce3/core/Common.h>
8namespace isce3 {
namespace math {
11#ifndef ISCE3_DEBUG_ROOT
13#define ISCE3_DEBUG_ROOT(x)
17CUDA_HOSTDEV
inline bool opposite_sign(T a, T b)
19 return std::signbit(a) ^ std::signbit(b);
23inline constexpr T epsilon = std::numeric_limits<T>::epsilon();
26CUDA_HOSTDEV
inline int count_bisection_steps(T a, T b, T tol)
28 return static_cast<int>(std::ceil(std::log2(std::abs((a - b) / tol))));
56template<
typename T,
typename Func>
57CUDA_HOSTDEV isce3::error::ErrorCode find_zero_brent(
58 T a, T b, Func f,
const T tol, T* root)
60 using namespace isce3::error;
62 if (root ==
nullptr) {
63 return ErrorCode::NullDereference;
67 return ErrorCode::InvalidTolerance;
76 T c, d, e, fa, fb, fc, p, q, r, s, tol1;
77 ISCE3_DEBUG_ROOT(
const char* step_type;)
82 return ErrorCode::Success;
87 return ErrorCode::Success;
91 if (!opposite_sign(fa, fb)) {
92 return ErrorCode::InvalidInterval;
99 ISCE3_DEBUG_ROOT(printf(
"b,a,step_type,x,f(x)\n");)
106 tol1 = tol > T(0) ? tol : epsilon<T>;
107 const int maxiter = 3 * count_bisection_steps(a, b, tol1);
108 for (
int i = 0; i < maxiter; ++i) {
113 if (abs(fc) < abs(fb)) {
123 tol1 = 2 * epsilon<T> * abs(b) + T(0.5) * tol;
125 const T xm = T(0.5) * (c - b);
129 if ((abs(xm) <= tol1) || (fb == T(0))) {
131 return ErrorCode::Success;
136 if ((abs(e) < tol1) || (abs(fa) <= abs(fb))) {
138 if (abs(e) < tol1) { step_type =
"bisect1"; }
else {
139 step_type =
"bisect2";
149 ISCE3_DEBUG_ROOT(step_type =
"linear";)
154 ISCE3_DEBUG_ROOT(step_type =
"quadratic";)
157 p = s * (2 * xm * q * (q - r) - (b - a) * (r - T(1)));
158 q = (q - T(1)) * (r - T(1)) * (s - T(1));
175 if (((2 * p) >= (3 * xm * q - abs(tol1 * q))) ||
176 (p >= abs(T(0.5) * s * q))) {
179 if ((2 * p) >= (3 * xm * q - abs(tol1 * q))) {
180 step_type =
"bisect3";
181 }
else { step_type =
"bisect4"; })
191 if (abs(d) <= tol1) {
193 ISCE3_DEBUG_ROOT(step_type =
"nudge_left";)
196 ISCE3_DEBUG_ROOT(step_type =
"nudge_right";)
204 printf(
"%.17g,%.17g,%s,%.17g,%.17g\n", a, c, step_type, b, fb);)
208 if (!opposite_sign(fb, fc)) {
215 return ErrorCode::FailedToConverge;
221template<
typename T,
typename Func>
222CUDA_HOSTDEV isce3::error::ErrorCode find_zero_bisection_iter(
223 T a, T b, Func f,
int niter, T* root)
225 using namespace isce3::error;
226 if (root ==
nullptr) {
227 return ErrorCode::NullDereference;
230 return ErrorCode::InvalidTolerance;
232 T midpoint, fa = f(a), fb = f(b);
235 return ErrorCode::Success;
240 return ErrorCode::Success;
242 if (!opposite_sign(fa, fb)) {
243 return ErrorCode::InvalidInterval;
245 ISCE3_DEBUG_ROOT(printf(
"b,a,step_type,x,f(x)\n");)
246 for (
int i = 0; i < niter; ++i) {
247 midpoint = (a + b) / 2;
248 const T fmid = f(midpoint);
249 if (fmid == T(0))
break;
250 ISCE3_DEBUG_ROOT(printf(
251 "%.17g,%.17g,bisect,%.17g,%.17g\n", a, b, midpoint, fmid);)
252 if (opposite_sign(fa, fmid)) {
261 return ErrorCode::Success;
265template<
typename T,
typename Func>
266CUDA_HOSTDEV isce3::error::ErrorCode find_zero_bisection(
267 T a, T b, Func f, T tol, T* root)
273 return isce3::error::ErrorCode::InvalidTolerance;
275 const int niter = count_bisection_steps(a, b, tol);
276 ISCE3_DEBUG_ROOT(printf(
"bisection steps = %d\n", niter);)
277 return find_zero_bisection_iter(a, b, f, niter, root);
base interpolator is an abstract base class
Definition BinarySearchFunc.cpp:5