определить количество слагаемых Ряда Маклорена
Определить, сколько слагаемых ряда Маклорена потребуется, чтобы вычислить значение функции е^x с заданной точностью эпсилон
Нужно искать сумму ряда, пока она не станет в промежут Exp(x) - eps < sum < exp(x) + eps, но не могу понять как это в виде кода записать
Ответы (3 шт):
Создайте 4 переменные:
-
- Первая, пусть будет вещественным числом
sum - Очевидно думаю для чего она
- Первая, пусть будет вещественным числом
-
- Вторая, целочисленное число например
count - Она будет отвечать за кол-во слагаемых
- Вторая, целочисленное число например
-
- Третья переменная будет число целочисленного типа
pow_x - Будет в роли числителя, т.е. степень
x
- Третья переменная будет число целочисленного типа
-
- И четвертая так же целочисленная переменная
fact - Будет отвечать за знаменатель, т.е. факториал
- И четвертая так же целочисленная переменная
Начальные значения переменных будут равны 1 т.к. мы возьмем сразу первое слагаемое (это 1).
Далее пишите цикл do ... while с условием, который вы написали в вопросе, но обратным (то есть чтобы пока сумма не входит в промежуток [exp(x) - eps; exp(x) + eps])
Ну а далее каждую итерацию:
- Умножаете
pow_xнаx factумножаете наcount(можно было переменную отдельную сделать для понимания, но ...)- Добавляете к сумме, частное числителя и знаменателя.
- Увеличиваете
countна единицу
Если все правильно, то при x = 1, eps = 1e-7 вы должны получить на выходе 11 слагаемых.
Никогда так не делал, но ниже я выложу ссылку на код, который полностью объяснен выше. Делаю это для того чтобы, если вы попробуете, но у вас не будет получатся, то вы могли посмотреть пример реализации. Я обижусь если вы просто скопируете код. А вот и код. Удачи! :)
Код работает для e^2, e^3, но когда вы вызываете для e^5, происходит переполнение разрядной сетки и цикл итерируется бесконечно, но думаю этого достаточно.
#include <math>
#include <iostream>
double getEpsilon(std::uint32_t order) {
return std::pow(10.0, -static_cast<double>(order));
}
std::vector<int> already_calculated_factorials = { 1, 1 };
std::uint32_t factorial(std::uint32_t number) {
if (number < already_calculated_factorials.size()) {
return already_calculated_factorials.at(number);
}
if (number == already_calculated_factorials.size()) {
const auto last_fact = already_calculated_factorials.back();
already_calculated_factorials.emplace_back(number * last_fact);
return already_calculated_factorials.back();
}
while (already_calculated_factorials.size() < number) {
const auto curr_num = already_calculated_factorials.size();
const auto last_fact = already_calculated_factorials.back();
already_calculated_factorials.emplace_back(curr_num * last_fact);
}
return already_calculated_factorials.back();
}
double calculateExponenta(double x, double epsilon) {
double macloren_sum = 0;
std::uint32_t number_of_members = 0;
const auto std_exp_value = std::exp(x);
while (std::abs(macloren_sum - std_exp_value) >= epsilon) {
macloren_sum += std::pow(x, static_cast<double>(number_of_members)) / factorial(number_of_members);
number_of_members++;
}
return macloren_sum;
}
int main() {
calculateExponenta(2, getEpsilon(1));
return 0;
}
Пояснения по коду
- Факториал вычисляется на основе уже предыдущих вычислений дабы не повторять лишние итерации
- У нас есть значение "истино верного" значения библиотечной функции
std_exp_value = std::exp(x); - У нас есть сумма ряда Маклорена
macloren_sum. В цикле мы производим суммирование.std::pow(x, static_cast<double>(number_of_members)) / factorial(number_of_members);соответствует формуле x^n/n!
Странно определять количество нужных слагаемых сравнивая частичную сумму со значением функции. Если мы умеем вычислять функцию точно, зачем возиться с рядом?
В случае ряда Маклорена/Тейлора можно оценить остаточный член в форме Лагранжа. Формула для нашего конкретного ряда упрощается до
x >= 0: R(n, x) <= 2*L(n, x)*S(n, x) / (1 - L(n, x)^2), если L(n, x) < 1
x < 0: R(n, x) <= L(n, x)
где
a(n, x) = x^n / n! - член ряда Маклорена,
L(n, x) = |a(n + 1, x)| - абсолютная величина следующего члена ряда Маклорена,
S(n, x) = sum(a(i, x) | 0 <= i <= n)) - частичная сумма ряда Маклорена,
R(n, x) = |e^x - S(n, x)| - остаточный член, ошибка, невязка,
разница между частичной суммой и самой фунцией.
С помощью этих формул мы может оценить размер частичной суммы не вычисляя саму функцию:
// g++ -std=c++11 -pedantic -Wall -Wextra maclaurin_exp.cpp
#include <cmath>
#include <iostream>
#include <limits>
void approximate(double eps, double x, int &sn, double &sum) {
double s = 0;
double a = 1;
for (int n = 0; ; ++n) {
s += a;
a *= x / (n + 1);
double l = std::abs(a);
if (x >= 0) {
if (l < 1 && 2 * l * s / (1 - l * l) <= eps) {
sn = n;
sum = s;
break;
}
} else {
if (l <= eps) {
sn = n;
sum = s;
break;
}
}
}
}
int main() {
std::cout.precision(std::numeric_limits<double>::max_digits10);
while (true) {
double eps;
std::cout << "\neps: ";
if (!(std::cin >> eps)) {
break;
}
double x;
std::cout << "x: ";
if (!(std::cin >> x)) {
break;
}
int n;
double y;
approximate(eps, x, n, y);
double error = std::abs(std::exp(x) - y);
std::cout
<< "eps = " << eps
<< ", x = " << x
<< ", n = " << n
<< ", y = " << y
<< ", error " << error << ' ' << ((error < eps) ? "OK" : "ERROR")
<< '\n';
}
}
Пример:
$ g++ -std=c++11 -pedantic -Wall -Wextra maclaurin_exp.cpp && ./a.out
eps: 0.0001
x: 0.1
eps = 0.0001, x = 0.10000000000000001, n = 3, y = 1.1051666666666666, error 4.2514089810818945e-06 OK
eps: 0.0001
x: 1
eps = 0.0001, x = 1, n = 8, y = 2.71827876984127, error 3.0586177750535626e-06 OK
eps: 0.0001
x: 10
eps = 0.0001, x = 10, n = 41, y = 22026.465794805794, error 9.2404661700129509e-10 OK
eps: 0.0001
x: 0
eps = 0.0001, x = 0, n = 0, y = 1, error 0 OK
eps: 0.0001
x: -0.1
eps = 0.0001, x = -0.10000000000000001, n = 3, y = 0.90483333333333338, error 4.0847026261392472e-06 OK
eps: 0.0001
x: -1
eps = 0.0001, x = -1, n = 7, y = 0.36785714285714288, error 2.2298314299451505e-05 OK
eps: 0.0001
x: -10
eps = 0.0001, x = -10, n = 33, y = 1.9092257563066713e-05, error 2.6307672199418141e-05 OK
