Каков наилучший подход к вычислению пределов функций? - PullRequest
3 голосов
/ 20 марта 2012

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

У меня уже есть оценщик функциональных выражений, который наверняка пригодится. Моя идея состоит в том, чтобы рассчитать его следующим образом: я даю параметру несколько значений, которые становятся все ближе и ближе к точке, но не достигают точки. В конце я вижу, становится ли разница между двумя последовательными результатами меньше или больше ближе или дальше от 0. Если она становится меньше ближе, это означает, что предел конечен, бесконечен иначе. После этого легко приблизить результат.

Есть ли лучший подход к этому? Или я должен пойти с этим?

Приложение будет принимать функции, которые содержат следующие математические операторы: +,-,*,/,%,^, функции (например, пол, логарифмы, тригонометрия) и 3 функции условия (abs, min, max). Так, например, функция, которая имеет определенное значение для целочисленных значений и другое значение для нецелых значений, не принимается.

Ответы [ 5 ]

3 голосов
/ 20 марта 2012

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

, но комментарий, который вы получили с wolframalpha, великолепен: пример: это именно то, что вам нужно

2 голосов
/ 20 марта 2012

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

Мы определяем f следующим образом:

  • f(x) = 0, если x - рациональное число
  • f(x) = 1, если x - не рациональное число

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

Ваш метод скажет, что предел f в точке, например, 5, равен 0, но f вообще не имеет ограничения.

1 голос
/ 20 марта 2012

Я просто собирался написать краткий комментарий, но чем больше я думал об этом, тем больше я приходил к выводу, что ответ на ваш вопрос заключается в том, что вы не должны соглашаться с вашим предложением. В вашем предложении есть округлость: найти предел функции, которую вы предлагаете, чтобы предоставить вашей системе ряд входов, оценка которых стремится к (предполагаемому) пределу функции. Как бы вы начали, не имея представления о том, что предел? Или вы хотите реализовать программу, которая находит пределы функций, которые вы уже знаете? Этакий искусственный идиот, который всегда будет знать меньше тебя?

Что касается того, что вы должны сделать, то сначала поймите, что это на самом деле довольно сложная для реализации функция и что не будет общего решения, которое будет работать для всех функций, даже для всех хороших, хорошо функционирующих функций. Возможно, вам будет полезно посмотреть, как это делает Sage (http://www.sagemath.org/), или любая другая система компьютерной алгебры с открытым исходным кодом, о которой вы знаете.

0 голосов
/ 04 мая 2019

Хотя трудно непосредственно найти предел, вы можете довольно хорошо оценить его в C #, используя константу double.Epsilon, чтобы найти чрезвычайно близкое значение.Это поле является константой для наименьшего числа, которое может быть представлено двойным числом с плавающей запятой, поэтому мы будем использовать его, чтобы найти предельно близкое значение к значению x и вставить его в функцию.

Вот пример:

using System;

namespace LimitsTest
{
    class Functions
    {
        public static double OneDividedByX(double x)
        {
            return 1 / x;
        }

        public static double XDividedByX(double x)
        {
            return x / x;
        }

        public static double OneDividedByXSquared(double x)
        {
            return 1 / Math.Pow(x, 2);
        }

        public static double XDividedByXPlusTwo(double x)
        {
            return x / (x + 2);
        }
    }

    class Program
    {
        static double LeftLimit(double x, Func<double, double> function)
        {
            return function(x - double.Epsilon);
        }

        static double RightLimit(double x, Func<double, double> function)
        {
            return function(x + double.Epsilon);
        }

        static double Limit(double x, Func<double, double> function)
        {
            double right = LeftLimit(x, function);
            double left = RightLimit(x, function);

            return (right == left) ? right : double.NaN;
        }

        static void ShowLimits(double x, string description, Func<double, double> function)
        {
            Console.WriteLine("{0} at {1}: {2}", description, x, function(x));
            Console.WriteLine("Limit of {0} as approached from the left of {1}: {2}",
                description, x, LeftLimit(x, function));
            Console.WriteLine("Limit {0} as approached from the right of {1}: {2}",
                description, x, RightLimit(x, function));
            Console.WriteLine("Limit of {0} as approached from {1}: {2}",
                description, x, Limit(x, function));
            Console.WriteLine();
        }

        static void Main(string[] args)
        {
            ShowLimits(0, "1 / x", Functions.OneDividedByX);
            ShowLimits(0, "x / x", Functions.XDividedByX);
            ShowLimits(0, "1 / x^2", Functions.OneDividedByXSquared);
            ShowLimits(-2, "x / (x + 2)", Functions.XDividedByXPlusTwo);

            Console.ReadLine();
        }
    }
}
0 голосов
/ 25 февраля 2019

То, как я это сделал, сначала применил Тейлора, чтобы найти оценку коэффициентов для данной функции, но сдвинул функцию влево на предел x. Затем из их заданного коэффициента, равного nan к 0. Затем просто вычислите функцию по заданному значению x.


#include <iostream>
#include <vector>
#include <math.h>

double getDerivitive(unsigned derivitive, double x, double cx, const std::function<double(double)> &f) {
    if (derivitive == 0) return f(x);

    double newCx = derivitive * cx;

    return (getDerivitive(derivitive - 1, x+newCx, cx, f) - getDerivitive(derivitive - 1, x-newCx, cx, f)) / (2*newCx);
}
std::vector<double> getCoefficient(unsigned precision, const std::function<double(double)> &f) {

    std::vector<double> coeffs(precision, 0.0);
    double iFactorial = 1;
    for (unsigned i = 0; i < precision; i++) {

        coeffs[i] = getDerivitive(i, 0.0, 0.01, f) / iFactorial;

        iFactorial *= (i+1);
    }

    return coeffs;
}

double getValueAt(double x, const std::vector<double> &coeffs) {

    double total = 0;

    double xToTheI = 1;
    for (unsigned i = 0; i < coeffs.size(); i++) {

        total += coeffs[i] * xToTheI;

        xToTheI *= x;
    }

    return total;
}

double getLimit(double x, const std::function<double(double)> &f) {

    std::function<double(double)> newFunc = [&](double atX) {
        return f(x + atX);
    };

    std::vector<double> coefficients = getCoefficient(10, newFunc);

    if (isnan(coefficients[0])) {
        coefficients[0] = newFunc(0.00001);

        if (abs(coefficients[0]) < 0.0001) {
            coefficients[0] = 0;
        }
    }

    for (unsigned i = 0; i < coefficients.size(); i++) {
        if (isnan(coefficients[i])) {
            coefficients[i] = 0;
        }
    }

    return getValueAt(0, coefficients);
}

int main(int argc, const char * argv[]) {


    std::function<double(double)> cosFTest = [](double x) {
        return cos(x);
    };

    std::cout << "Limit of cos(0)  ==  " << getLimit(0, cosFTest) << std::endl;

    std::function<double(double)> sinOverXTest = [](double x) {
        return sin(x)/x;
    };

    std::cout << "Limit of sin(x)/x  ==  " << getLimit(0, sinOverXTest) << std::endl;

    std::function<double(double)> polynomial = [](double x) {
        return (x*x) / x;
    };

    std::cout << "Limit of x^2 / x  ==  " << getLimit(0, polynomial) << std::endl;

    std::function<double(double)> funcTestInfinity = [](double x) {
        return 1.0/x;
    };

    std::cout << "Limit at 1/x apraoches infinity ==  " << getLimit(INFINITY, funcTestInfinity) << std::endl;

    return 0;
}
...