Математическая функция дифференцирования с C #? - PullRequest
5 голосов
/ 17 декабря 2008

Я вижу, что могу объявить функцию с (скажем)

public double Function(double parameter)

а что если я захочу взять производную от этой функции?

Ответы [ 5 ]

33 голосов
/ 17 декабря 2008

Вы не можете вычислить точную производную функции с помощью компьютерной программы (если вы не занимаетесь символической математикой ... но это другая, более сложная тема).

Существует несколько подходов к вычислению числовой производной функции. Простейшим является центрированный трехточечный метод:

  • Возьми небольшое число h
  • Оценка [f(x+h) - f(x-h)] / 2h
  • Вуаля, приближение f '(x), только с двумя оценками функций

Другим подходом является центрированный пятиточечный метод:

  • Взять небольшое число ч
  • Оценка [f(x-2h) - 8f(x-h) + 8f(x+h) - f(x+2h)] / 12h
  • Вуаля, лучшее приближение f '(x), но для этого требуется больше оценок функций

Другая тема - как реализовать это с помощью C #. Во-первых, вам нужен делегат, представляющий функцию, которая отображает подмножество действительных чисел на другое подмножество действительных чисел:

delegate double RealFunction(double arg);

Затем вам нужен маршрут, который оценивает производную:

public double h = 10e-6; // I'm not sure if this is valid C#, I'm used to C++

static double Derivative(RealFunction f, double arg)
{
    double h2 = h*2;
    return (f(x-h2) - 8*f(x-h) + 8*f(x+h) - f(x+h2)) / (h2*6);
}

Если вы хотите объектно-ориентированную реализацию, вы должны создать следующие классы:

interface IFunction
{
    // Since operator () can't be overloaded, we'll use this trick.
    double this[double arg] { get; }
}

class Function : IFunction
{
    RealFunction func;

    public Function(RealFunction func)
    { this.func = func; }

    public double this[double arg]
    { get { return func(arg); } }
}

class Derivative : IFunction
{
    IFunction func;
    public static double h = 10e-6;

    public Derivative(IFunction func)
    { this.func = func; }

    public double this[double arg]
    {
        get
        {
            double h2 = h*2;
            return (
                func[arg - h2] - func[arg + h2] +
                ( func[arg + h]  - func[arg - h] ) * 8
                ) / (h2 * 6);
        }
    }
}
7 голосов
/ 17 декабря 2008

Если вы думаете о символических манипуляциях с формулами, то вам лучше делать деривации на таких языках, как Maple или Mathematica. Они предназначены для символьных вычислений.

РЕДАКТИРОВАТЬ: Если Maple и Mathematica слишком дороги для вас, то есть другие варианты. В Википедии есть довольно полный список пакетов компьютерной алгебры. http://en.wikipedia.org/wiki/Comparison_of_computer_algebra_systems

1 голос
/ 24 июля 2015

Другой подход может заключаться в том, чтобы использовать методы расширений, используя хорошо известное определение производного числа, и соответственно вычислять его приближение.

Как уже упоминалось, это довольно просто для числового подхода, а не символического:

public partial static class IEnumerableExtensions
{
    public static IEnumerable<Double> Derivate1<TSource>(this IEnumerable<TSource> source, Func<TSource, Double> selectorX, Func<TSource, Double> selectorY)
    {
        var enumerator = source.GetEnumerator();

        enumerator.Reset();
        enumerator.MoveNext();

        var itemPrevious = enumerator.Current;
        var itemNext = default(TSource);

        while (enumerator.MoveNext())
        {
            itemNext = enumerator.Current;

            var itemPreviousX = selectorX(itemPrevious);
            var itemPreviousY = selectorY(itemPrevious);

            var itemNextX = selectorX(itemNext);
            var itemNextY = selectorY(itemNext);

            var derivative = (itemNextY - itemPreviousY) / (itemNextX - itemPreviousX);

            yield return derivative;

            itemPrevious = itemNext;
        }
    }
}

или, если вам больше нравится foreach мода

public partial static class IEnumerableExtensions
{
     public static IEnumerable<Double> Derivate2<TSource>(IEnumerable<TSource> source, Func<TSource, Double> selectorX, Func<TSource, Double> selectorY)
     {
         var itemPrevious = source.First();

         source = source.Skip(1);

         foreach (var itemNext in source)
         {
             var itemPreviousX = selectorX(itemPrevious);
             var itemPreviousY = selectorY(itemPrevious);

             var itemNextX = selectorX(itemNext);
             var itemNextY = selectorY(itemNext);

             var derivative = (itemNextY - itemPreviousY) / (itemNextX - itemPreviousX);

             yield return derivative;

             itemPrevious = itemNext;
        }
    }
}

Вы можете изменить все, как показано ниже:

public static partial class MathHelpers
{
    public static Double Derivate(Double xPrevious, Double xNext, Double yPrevious, Double yNext)
    {
        var derivative = (yNext - yPrevious)/(xNext - xPrevious);

        return derivative;
    }
}

public static class IEnumerableExtensions
{
     public static IEnumerable<Double> Derivate<TSource>(IEnumerable<TSource> source, Func<TSource, Double> selectorX, Func<TSource, Double> selectorY)
     {
         var itemPrevious = source.First();

         source = source.Skip(1);

         foreach (var itemNext in source)
         {
             var derivative = MathHelpers.Derivate(selectorX(itemPrevious), selectorX(itemNext), selectorY(itemPrevious), selectorY(itemNext));

             yield return derivative;

             itemPrevious = itemNext;
        }
    }
}
1 голос
/ 17 декабря 2008

Вы думаете о лямбда-выражениях?

По сути, вы можете передать функцию в функцию.

Так что подумайте о сортировке по объекту. В зависимости от характера объекта поможет определить, как объекты сортируются.

Но вы все равно можете создать общую функцию сортировки, а затем передать, как сравнивать объекты.

0 голосов
/ 17 декабря 2008

Если вы написали функцию, она уже получена.

И, учитывая, что это функция int, я предполагаю, что вы не имеете в виду определение исчисления «получить».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...