Click here to Skip to main content
15,886,110 members
Articles / Programming Languages / C# 4.0

Three Methods for Root-finding in C#

Rate me:
Please Sign up or sign in to vote.
4.85/5 (26 votes)
26 Jun 2014BSD5 min read 92K   3.3K   52  
Three numerical algorithms for solving equations, each implemented in C#
using System;

namespace DemoApplication
{
    class Demo
    {
        // Note that this function is increasing for x < 1 and decreasing for x > 1.
        static double f(double x)
        {
            return x*Math.Exp(-x);
        }

        // Derivative of f
        static double fprime(double x)
        {
            return (1.0 - x) * Math.Exp(-x);
        }

        static void Main(string[] args)
        {
            const double tolerance = 1e-7;
            double expected, computed, target;



            // Test root finder on range where f is increasing.
            // f(-1) = target, so -1 is the exact answer.
            target = -2.71828182845905;
            expected = -1.0;

            Console.WriteLine("Test root-finding on region where function is increasing.\n"); 

            computed = RootFinding.Bisect(new FunctionOfOneVariable(f), -4, 1, tolerance, target);
            PrintResults("Bisect", computed, expected);

            computed = RootFinding.Brent(new FunctionOfOneVariable(f), -4, 1, tolerance, target);
            PrintResults("Brent ", computed, expected);

            computed = RootFinding.Newton(new FunctionOfOneVariable(f), fprime, 0.0, tolerance, target);
            PrintResults("Newton", computed, expected);


            // Test root finder on range where f is decreasing.
            // f(5) = target, so 5 is the exact answer.
            target = 0.0336897349954273;
            expected = 5.0;

            Console.WriteLine("Test root-finding on region where function is increasing.\n");

            computed = RootFinding.Bisect(new FunctionOfOneVariable(f), 3, 7.1, tolerance, target);
            PrintResults("Bisect", computed, expected);

            computed = RootFinding.Brent(new FunctionOfOneVariable(f), 3, 7.1, tolerance, target);
            PrintResults("Brent ", computed, expected);

            computed = RootFinding.Newton(new FunctionOfOneVariable(f), fprime, 4.0, tolerance, target);
            PrintResults("Newton", computed, expected);


            // Demonstrate validation.
            Console.WriteLine("");
            try
            {
                // There is no solution in the interval since f(3) and f(7) are both positive.
                // This should raise an exception.
                double x = RootFinding.Brent(new FunctionOfOneVariable(f), 3, 7, tolerance, 0.0);
                Console.WriteLine("WARNING: Missing validation logic. Should not have gotten here.");
            }
            catch(ArgumentException e)
            {
                Console.WriteLine("Correctly threw an exception when given bad input.");
                Console.WriteLine(e.Message);
            }

            Console.WriteLine();

            // Demonstrate efficiency of each method.
            int iterationsUsed;
            double errorEstimate;

            // Solve f(x) = 0.2 to 10 decimal places
            RootFinding.Bisect(new FunctionOfOneVariable(f), 1.0, 5.0, 1e-10, 0.2, out iterationsUsed, out errorEstimate);
            PrintEfficiencyAndAccuracy("Bisect", iterationsUsed, errorEstimate);
            RootFinding.Brent(new FunctionOfOneVariable(f), 1.0, 5.0, 1e-10, 0.2, out iterationsUsed, out errorEstimate);
            PrintEfficiencyAndAccuracy("Brent ", iterationsUsed, errorEstimate);
            RootFinding.Newton(new FunctionOfOneVariable(f), fprime, 2.0, 1e-10, 0.2, out iterationsUsed, out errorEstimate);
            PrintEfficiencyAndAccuracy("Newton", iterationsUsed, errorEstimate);
        }

        static void PrintResults(string method, double computed, double expected)
        {
            Console.WriteLine("Method:   {0}\nexpected: {1}\ncomputed: {2}\nerror:    {3}\n", method, expected, computed, Math.Abs(expected - computed));
        }

        static void PrintEfficiencyAndAccuracy(string method, int iterations, double error)
        {
            Console.WriteLine("Method:   {0}\niterations: {1}\nerror:     {2}\n", method, iterations, error);
        }
    }
}

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 BSD License


Written By
President John D. Cook Consulting
United States United States
I work in the areas of applied mathematics, data analysis, and data privacy.

Check out my blog or send me a note.

 


Comments and Discussions