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; | |
|             } | |
|         } | |
|     }; | |
| }
 | |
| 
 |