Top.Mail.Ru
Ответы

Не понимаю, почему не работает программа для поиска значения синуса рекуррентным способом

Здравствуйте! Целью, поставленной задачи, являлось программное решение для нахождения синуса. Нужно найти значение синуса с указанной точностью N и максимально возможной точностью N. В условии сказано, что надо использовать ряд Тейлора. НО вычисления должны быть рекуррентны, чтобы постоянно не высчитывать с самого начала каждый новый член ряда, а использовать для вычислений уже найденные значения. Буду благодарен за помощь.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
 #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; 
} 
Только авторизированные пользователи могут оставлять свои ответы
Дата
Популярность
Аватар пользователя
Новичок

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

12345678910111213141516171819202122232425262728293031323334353637
 #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 фактическая ошибка будет меньше, но всё равно алгоритм при очень больших по модулю аргументах синуса требуется совсем другой!

Аватар пользователя
Оракул
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
 #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;  
} 
 
Аватар пользователя
Гений
1234567891011121314151617181920212223242526
 #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-го члена".