Numerical Differentiation in C# QuickStart Sample
Illustrates how to approximate the derivative of a function in C#.
View this sample in: Visual Basic F# IronPython
using System;
// The numerical differentiation classes reside in the
// Numerics.NET.Calculus namespace.
using Numerics.NET.Calculus;
// Function delegates reside in the Numerics.NET
// namespace.
using Numerics.NET;
namespace Numerics.NET.QuickStart.CSharp
{
/// <summary>
/// Illustrates numerical differentiation using the
/// FunctionMath class in the Numerics.NET
/// namespace of Numerics.NET.
/// </summary>
class NumericalDifferentiationSample
{
static void Main(string[] args)
{
// The license is verified at runtime. We're using
// a 30 day trial key here. For more information, see
// https://numerics.net/trial-key
Numerics.NET.License.Verify("64542-18980-57619-62268");
// Numerical differentiation is a fairly simple
// procedure. Its accuracy is inherently limited
// because of unavoidable round-off error.
//
// All calculations are performed by static methods
// of the FunctionMath class. All methods are extension
// methods, so they can be applied to the delegates
// directly.
double result;
double estimatedError;
//
// Standard numerical differentiation.
//
// Central differences are the standard way of
// approximating the result of a function.
// For this to work, it must be possible to
// evaluate the target function on both sides of
// the point where the numerical result is
// requested.
// The function must be provided as a
// Func<double, double>. For more information about
// this delegate, see the FunctionDelegates
// QuickStart Sample.
Func<double, double> fCentral = Math.Cos;
Console.WriteLine("Central differences:");
// The actual calculation is performed by the
// CentralDerivative method.
result = fCentral.CentralDerivative(1.0);
Console.WriteLine($" Result = {result}");
Console.WriteLine($" Actual = {-Math.Sin(1.0)}");
// This method is overloaded. It has an optional
// out parameter that returns an estimate for the
// error in the result.
result = fCentral.CentralDerivative(1.0, out estimatedError);
Console.WriteLine("Estimated error = {0}",
estimatedError);
//
// Forward and backward differences.
//
// Some functions are not defined everywhere.
// If the result is required on a boundary
// of the domain where it is defined, the central
// differences method breaks down. This also happens
// if the function has a discontinuity close to the
// differentiation point.
//
// In these cases, either forward or backward
// differences may be used instead.
//
// Here is an example of a function that may require
// forward differences. It is undefined for
// x < -2:
Func<double, double> fForward = x => (x+2) * (x+2) * Math.Sqrt(x+2);
// Calculating the derivative using central
// differences returns NaN (Not a Number):
result = fForward.CentralDerivative(-2.0, out estimatedError);
Console.WriteLine("Using central differences may not work:");
Console.WriteLine($" Derivative = {result}");
Console.WriteLine($" Estimated error = {estimatedError}");
// Using the ForwardDerivative method does work:
Console.WriteLine("Using forward differences instead:");
result = fForward.ForwardDerivative(-2.0, out estimatedError);
Console.WriteLine($" Derivative = {result}");
Console.WriteLine($" Estimated error = {estimatedError}");
// The FBackward function at the end of this file
// is an example of a function that requires
// backward differences for differentiation at
// x = 0.
Func<double, double> fBackward = x => x > 0.0 ? 1.0 : Math.Sin(x);
Console.WriteLine("Using backward differences:");
result = fBackward.BackwardDerivative(0.0, out estimatedError);
Console.WriteLine($" Derivative = {result}");
Console.WriteLine($" Estimated error = {estimatedError}");
//
// Derivative function
//
// In some cases, it may be useful to have the
// derivative of a function in the form of a
// Func<double, double>, so it can be passed as
// an argument to other methods. This is very
// easy to do.
Console.WriteLine("Using delegates:");
// For central differences:
Func<double, double> dfCentral = fCentral.GetNumericalDifferentiator();
Console.WriteLine($"Central: f'(1) = {dfCentral(1)}");
// For forward differences:
Func<double, double> dfForward = fForward.GetForwardDifferentiator();
Console.WriteLine($"Forward: f'(-2) = {dfForward(-2)}");
// For backward differences:
Func<double, double> dfBackward = fBackward.GetBackwardDifferentiator();
Console.WriteLine($"Backward: f'(0) = {dfBackward(0)}");
Console.Write("Press Enter key to exit...");
Console.ReadLine();
}
}
}