Click here to Skip to main content
15,894,343 members
Articles / Programming Languages / C#

One dimensional root finding algorithms

Rate me:
Please Sign up or sign in to vote.
4.81/5 (14 votes)
23 Oct 2006CPOL4 min read 48.7K   1.3K   32  
A set of popular algorithms to solve the equation f(x)=0 in one dimension.
using System;

namespace RootFinding
{
	public delegate double UnaryFunction(double x);

	public abstract class RootFinder
	{

	#region Constants
		protected static string m_InvalidRange="Invalid range while finding root";
		protected static string m_AccuracyNotReached="The accuracy couldn't be reached with the specified number of iterations";
		protected static string m_RootNotFound="The algorithm ended without root in the range";
		protected static string m_RootNotBracketed="The algorithm could not start because the root seemed not to be bracketed";
		protected static string m_InadequatedAlgorithm="This algorithm is not able to solve this equation";
		protected static double double_Accuracy=9.99200722162641E-16;
	#endregion Constants

	#region Variables
		private static int m_NbIterDefaultMax=30;
		private static double m_DefaultAccuracy=1.0E-04;
		protected int m_NbIterMax;
		protected double m_xmin, m_xmax;
		protected double m_Accuracy;
		protected UnaryFunction m_f,m_Of;
		private double m_BracketingFactor=1.6;

	#endregion Variables

	#region Construction
		/// <summary>Constructor.</summary>
		/// <param name="f">A continuous function.</param>
		public RootFinder(UnaryFunction f)
			: this(f,m_NbIterDefaultMax,m_DefaultAccuracy) {
		}

		public RootFinder(UnaryFunction f,int niter,double acc) {
			m_f=f;
			m_NbIterMax=niter;
			m_Accuracy=acc;
		}
	#endregion Construction

	#region Properties
		public double BracketingFactor {
			get { return m_BracketingFactor; }
			set { if(value<=0.0) throw new ArgumentOutOfRangeException(); m_BracketingFactor=value; }
		}
		public int Iterations {
			set { if(value<=0) throw new ArgumentOutOfRangeException(); m_NbIterMax = value; }
		}
		public double Accuracy {
			get { return m_Accuracy; }
			set { m_Accuracy=value; }
		}
	#endregion Properties

	#region Methods
		/// <summary>Detect a range containing at least one root.</summary>
		/// <param name="xmin">Lower value of the range.</param>
		/// <param name="xmax">Upper value of the range</param>
		/// <param name="factor">The growing factor of research. Usually 1.6.</param>
		/// <returns>True if the bracketing operation succeeded, else otherwise.</returns>
		/// <remarks>This iterative methods stops when two values with opposite signs are found.</remarks>
		public bool SearchBracketsOutward(ref double xmin, ref double xmax, double factor) {
			// Check the range
			if(xmin>=xmax) throw new RootFinderException(m_InvalidRange,0,new Range(xmin,xmax),0.0);
			double fmin, fmax;
			fmin = m_f(xmin);
			fmax = m_f(xmax);
			int iiter=0;
			do {
				if(Sign(fmin)!=Sign(fmax)) return (true);
				if(Math.Abs(fmin)<Math.Abs(fmax)) fmin=m_f(xmin+=factor*(xmin-xmax));
				else fmax=m_f(xmax+=factor*(xmax-xmin));
			} while(iiter++<m_NbIterMax);
			throw new RootFinderException(m_RootNotFound,iiter,new Range(fmin,fmax),0.0);
		}

		// Algorithmes de résolution
		/// <summary>Prototype algorithm for solving the equation f(x)=0.</summary>
		/// <param name="x1">The low value of the range where the root is supposed to be.</param>
		/// <param name="x2">The high value of the range where the root is supposed to be.</param>
		/// <param name="bracket">Determines whether a bracketing operation is required.</param>
		/// <returns>Returns the root with the specified accuracy.</returns>
		public virtual double Solve(double x1, double x2, bool bracket) {
			if(bracket) SearchBracketsOutward(ref x1,ref x2,m_BracketingFactor);
			m_xmin = x1; m_xmax = x2; return Find();
		}
		/// <summary>Prototype algorithm for solving the equation f(x)=y.</summary>
		/// <param name="x1">The low value of the range where the root is supposed to be.</param>
		/// <param name="x2">The high value of the range where the root is supposed to be.</param>
		/// <param name="y"></param>
		/// <param name="bracket">Determines whether a bracketing operation is required.</param>
		/// <returns>Returns the root with the specified accuracy.</returns>
		public virtual double Solve(double x1,double x2,double y,bool bracket) {
			m_Of=m_f;
			m_f=UnaryFunctions.Substract(m_Of,UnaryFunctions.Constant(y));
			double x=Solve(x1,x2,bracket);
			m_f=m_Of; m_Of=null;
			return x;
		}

		protected abstract double Find();

	#endregion Methods

	#region Helper methods
		protected void Swap(ref double x,ref double y) {
			double t=x; x=y; y=t;
		}
		/// <summary>Helper method useful for preventing rounding errors.</summary>
		/// <returns>a*sign(b)</returns>
		protected double Sign(double a,double b) {
			return b>=0?(a>=0?a:-a):(a>=0?-a:a);
		}
		internal static double Sign(double x) {
			return x>0?1.0:-1.0;
		}
	#endregion Helper methods

	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions