Не понимаю, почему не работает программа для поиска значения синуса рекуррентным способом
Здравствуйте! Целью, поставленной задачи, являлось программное решение для нахождения синуса. Нужно найти значение синуса с указанной точностью N и максимально возможной точностью N. В условии сказано, что надо использовать ряд Тейлора. НО вычисления должны быть рекуррентны, чтобы постоянно не высчитывать с самого начала каждый новый член ряда, а использовать для вычислений уже найденные значения. Буду благодарен за помощь.
#include <stdio.h>
#include <math.h>
#define _CRT_SECURE_NO_WARNINGS
// Определение значения эпсилон
#define LDBL_EPSILON pow(2,-63)
// Функция для вычисления максимально возможной точности через эпсилон
int max_accuracy(long double x, int n, long double e)
{
int i;
long double memory = x;
for (i = 0; i < n; i++)
{
memory *= -x * x / ((2 * i + 1) * (2 * i + 2));
// Проверяем условие окончания итераций
if (fabs(memory) < e)
{
break;
}
}
return i;
}
int main()
{
int n;
long double x, sum;
printf("input n:");
scanf_s("%d", &n);
printf("input x:");
scanf_s("%Lf", &x);
// Определение значения эпсилон
long double e = LDBL_EPSILON;
int maxN = max_accuracy(x, n, e); // Вычисление максимально возможной точности
// Итерации для вычисления синуса с помощью формулы Тейлора
sum = x;
long double member = x;
for (long double i = 0; i <= maxN; i++) {
member *= (-x * x / ((2 * i + 1) * (2 * i + 2)));
sum += member;
if (i == maxN) {
printf("given accuracy: %.50Lf\n", sum);
}
}
printf("sin max accuracy: %.50Lf\n", sum);
return 0;
}
Видите ли, если Вам надо вычислять синус в достаточно широких пределах с некоторой точностью, в том числе и с максимальной, то его, синус то есть, и нужно вычислять! А у Вас для этого верного кода вообще нет и в ответах его, естественно, тоже нет - там один дилетантизм! Вот как будет правильно со своими функциями:
#include <math.h>
#include <stdio.h>
#define tau 6.2831853071795864769252
double q;
double Abs(double x)
{
return x < 0. ? - x : x;
}
double Sin(double x, double eps)
{
q = 1.;
x -= tau * (long long)(x / tau);
double p = x, s = x, y = - x * x;
while (Abs(p) > eps)
{
q += 2.;
p *= y / (q * (q - 1.));
s += p;
}
return s;
}
int main()
{
double x, y, eps;
for (;;)
{
printf("x eps: ");
scanf("%lf%lf", &x, &eps);
y = Sin(x, eps);
printf("%20.17f, err = %13.6e (%.0f)\n",
y, y - sin(x), (q + 1) / 2);
}
}

В скобках - количество взятых слагаемых ряда Маклорена, err - абсолютная ошибка вычисленного значения синуса в сравнении со стандартной функцией sin из модуля math. Большие по модулю аргументы синуса совершенно обязательно приводить к небольшим, пользуясь тау-периодичностью этой функции, и ничего лишнего в итерационном цикле вычисления синуса быть не должно! Максимально возможная точность соответствует, например, вводимому эпсилону, равному нулю, а для слишком больших по модулю значениях аргумента синуса нужна вообще совершенно другая вычислительная схема! Сами же видите что получается при аргументе синуса, равному триллиону. С типом long double фактическая ошибка будет меньше, но всё равно алгоритм при очень больших по модулю аргументах синуса требуется совсем другой!
#include <stdio.h>
#include <math.h>
#define _CRT_SECURE_NO_WARNINGS
// Определение значения эпсилон
#define LDBL_EPSILON pow(2,-63)
// Функция для вычисления максимально возможной точности через эпсилон
int max_accuracy(long double x, int n, long double e)
{
int i;
long double memory = x;
for (i = 0; i < n; i++)
{
memory *= -x * x / ((2 * i + 1) * (2 * i + 2));
// Проверяем условие окончания итераций
if (fabs(memory) < e)
{
break;
}
}
return i;
}
int main()
{
int n;
long double x, sum;
printf("input n:");
scanf_s("%d", &n);
printf("input x:");
scanf_s("%Lf", &x);
// Определение значения эпсилон
long double e = LDBL_EPSILON;
int maxN = max_accuracy(x, n, e); // Вычисление максимально возможной точности
// Итерации для вычисления синуса с помощью формулы Тейлора
sum = x;
long double member = x;
for (int i = 0; i <= maxN; i++) {
member *= (-x * x / ((2 * i + 1) * (2 * i + 2)));
sum += member;
if (i == maxN) {
printf("given accuracy: %.50Lf\n", sum);
}
}
printf("sin max accuracy: %.50Lf\n", sum);
return 0;
}
#include <stdio.h>
#include <math.h>
#define _CRT_SECURE_NO_WARNINGS
int main()
{
int n = 2;
long double x, sum_max=0, sum_e=0, e;
printf("input eps:");
scanf_s("%Lf", &e);
printf("input x:");
scanf_s("%Lf", &x);
// Итерации для вычисления синуса с помощью формулы Тейлора
long double member = x;
while (sum_max + member != sum_max) //условие максимальной точности
{
if (fabs(member) > e) sum_e += member; //условие заданной точности
sum_max += member;
member *= -x*x;
member /= n * (n + 1);
n += 2;
}
printf("given accuracy: %.16Lf\n", sum_e);
printf("sin max accuracy: %.16Lf\n", sum_max);
return 0;
}
обычно double имеет размер 8 байт и точность около 16 знаков, 50 знаков - это явно лишнее (по крайней мере для моего MSVS). Себе можете любую ставить.
Под точностью подразумевают не количество итераций (как у вас), а величина очередного члена ряда.
Максимальная точность достигается когда очередной член ряда не оказывает влияния на сумму.
ну и ошибка в знаменателе ряда. там не должно быть 2*... Просто (i+1)*(i+2). а шаг итерации i = 2. Цикл по i ставится если задание звучит как "найти сумму ряда до i-го члена".