You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
5.4 KiB
169 lines
5.4 KiB
// David Eberly, Geometric Tools, Redmond WA 98052
|
|
// Copyright (c) 1998-2021
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// https://www.boost.org/LICENSE_1_0.txt
|
|
// https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
|
|
// Version: 4.0.2019.08.13
|
|
|
|
#pragma once
|
|
|
|
#include <functional>
|
|
|
|
// Compute a root of a function F(t) on an interval [t0, t1]. The caller
|
|
// specifies the maximum number of iterations, in case you want limited
|
|
// accuracy for the root. However, the function is designed for native types
|
|
// (Real = float/double). If you specify a sufficiently large number of
|
|
// iterations, the root finder bisects until either F(t) is identically zero
|
|
// [a condition dependent on how you structure F(t) for evaluation] or the
|
|
// midpoint (t0 + t1)/2 rounds numerically to tmin or tmax. Of course, it
|
|
// is required that t0 < t1. The return value of Find is:
|
|
// 0: F(t0)*F(t1) > 0, we cannot determine a root
|
|
// 1: F(t0) = 0 or F(t1) = 0
|
|
// 2..maxIterations: the number of bisections plus one
|
|
// maxIterations+1: the loop executed without a break (no convergence)
|
|
|
|
namespace gte
|
|
{
|
|
template <typename Real>
|
|
class RootsBisection
|
|
{
|
|
public:
|
|
// Use this function when F(t0) and F(t1) are not already known.
|
|
static unsigned int Find(std::function<Real(Real)> const& F, Real t0,
|
|
Real t1, unsigned int maxIterations, Real& root)
|
|
{
|
|
// Set 'root' initially to avoid "potentially uninitialized
|
|
// variable" warnings by a compiler.
|
|
root = t0;
|
|
|
|
if (t0 < t1)
|
|
{
|
|
// Test the endpoints to see whether F(t) is zero.
|
|
Real f0 = F(t0);
|
|
if (f0 == (Real)0)
|
|
{
|
|
root = t0;
|
|
return 1;
|
|
}
|
|
|
|
Real f1 = F(t1);
|
|
if (f1 == (Real)0)
|
|
{
|
|
root = t1;
|
|
return 1;
|
|
}
|
|
|
|
if (f0 * f1 > (Real)0)
|
|
{
|
|
// It is not known whether the interval bounds a root.
|
|
return 0;
|
|
}
|
|
|
|
unsigned int i;
|
|
for (i = 2; i <= maxIterations; ++i)
|
|
{
|
|
root = (Real)0.5 * (t0 + t1);
|
|
if (root == t0 || root == t1)
|
|
{
|
|
// The numbers t0 and t1 are consecutive
|
|
// floating-point numbers.
|
|
break;
|
|
}
|
|
|
|
Real fm = F(root);
|
|
Real product = fm * f0;
|
|
if (product < (Real)0)
|
|
{
|
|
t1 = root;
|
|
f1 = fm;
|
|
}
|
|
else if (product > (Real)0)
|
|
{
|
|
t0 = root;
|
|
f0 = fm;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
// The interval endpoints are invalid.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// If f0 = F(t0) and f1 = F(t1) are already known, pass them to the
|
|
// bisector. This is useful when |f0| or |f1| is infinite, and you
|
|
// can pass sign(f0) or sign(f1) rather than then infinity because
|
|
// the bisector cares only about the signs of f.
|
|
static unsigned int Find(std::function<Real(Real)> const& F, Real t0,
|
|
Real t1, Real f0, Real f1, unsigned int maxIterations, Real& root)
|
|
{
|
|
// Set 'root' initially to avoid "potentially uninitialized
|
|
// variable" warnings by a compiler.
|
|
root = t0;
|
|
|
|
if (t0 < t1)
|
|
{
|
|
// Test the endpoints to see whether F(t) is zero.
|
|
if (f0 == (Real)0)
|
|
{
|
|
root = t0;
|
|
return 1;
|
|
}
|
|
|
|
if (f1 == (Real)0)
|
|
{
|
|
root = t1;
|
|
return 1;
|
|
}
|
|
|
|
if (f0 * f1 > (Real)0)
|
|
{
|
|
// It is not known whether the interval bounds a root.
|
|
return 0;
|
|
}
|
|
|
|
unsigned int i;
|
|
root = t0;
|
|
for (i = 2; i <= maxIterations; ++i)
|
|
{
|
|
root = (Real)0.5 * (t0 + t1);
|
|
if (root == t0 || root == t1)
|
|
{
|
|
// The numbers t0 and t1 are consecutive
|
|
// floating-point numbers.
|
|
break;
|
|
}
|
|
|
|
Real fm = F(root);
|
|
Real product = fm * f0;
|
|
if (product < (Real)0)
|
|
{
|
|
t1 = root;
|
|
f1 = fm;
|
|
}
|
|
else if (product > (Real)0)
|
|
{
|
|
t0 = root;
|
|
f0 = fm;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
// The interval endpoints are invalid.
|
|
return 0;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|