2017-02-14 1 views
0

Я пытаюсь аппроксимировать синус (x) в C с использованием серии Тейлора и приближения Стирлинга для факториалов, но я получаю действительно странные ответы для n < 5 и -0 для любого n => 5. Я буквально только начал изучать вчера, так что я был бы признателен, если некоторые более опытные программисты могли бы взглянуть на это и скажите мне, что это неправильноАппроксимирующий синус (x) с серией Тейлора в C и имеющий множество проблем

ряд Тейлора Sine

приближения Стирлинга факториалов

#include <stdio.h> 
#include <math.h> 

int main(){ 

float x,n,s,i,e,p,f,r; 
f=M_PI; 
e=2.7182818; 
s=0; 

printf("What value of sine do you want to apporximate?"); 
    scanf("%f", &x); 
printf("With what level of precision do you want to calculate it?"); 
    scanf("%f", &n); 
for(i=0;i<=n; ++i);{ 
    r=((2*i)+1); 
    p=(sqrt(2*r*f)*(pow((r/e),r))); 
    s=s+(((pow((-1),i))*(pow(x,((2*i)+1))))/p); 
} 
printf("the value of sine at %f is %f",x,s); 
} 
+0

Вы должны использовать 'double's вместо' float's и 'i' и' n' должны быть 'int's. –

+0

Здесь также мало нужно приближать факториал. Вычисляйте каждый термин поэтапно вместо этого, то есть путем последовательного умножения переменной терма на '(-x * x)/(i * (i + 1))' каждая итерация. – doynax

ответ

0

Эта линия

for(i = 0; i <= n; ++i);{ 

имеет дополнительную точку с запятой. Вы выполняете пустой цикл.

+3

И, кроме того, это уловит предупреждение в вашем компиляторе. Если вы начинаете с C, пожалуйста, включите все предупреждения и задайте только вопросы о том, что они означают, когда вы их видите, или избавляетесь от них, если вы их понимаете! – dave

0

Основываясь на вашем formulat это правильный код, но он генерирует неверный вывод, так что вам нужно снова проверить ваш formulat:

#include <stdio.h> 
#include <math.h> 

int main(){ 

double x,n,s,i,e,p,f; 
f=M_PI; 
e=2.7182818; 
s=0; 
int sign=0;// Adding this type to toggle the sign 

printf("What value of sine do you want to apporximate?"); 
    scanf("%lf", &x);// conversion specifier must be %lf for floating number 
printf("With what level of precision do you want to calculate it?"); 
    scanf("%lf", &n); 
for(i=1;i<=n; i=i+2){ // Correcting the for loop 
    p=sqrt(2*i*f)*pow((i/e),i); 
    s=s+(pow(-1,sign++)*pow(x,i))/p; 
} 
printf("the value of sine at %f is %f",x,s); 
} 
-1

Как sin() является периодической функцией, я никогда не должны идти дальше, чем один период для его расчета. Это упрощает слишком много математики, так как вам никогда не нужно вычислять большие числовые числа. Действительно, вам даже не нужно вычислять факториал для каждого члена в серии, так как коэффициенты могут быть получены от последнего, просто разделив предыдущий коэффициент на (n-1) и n. если ваш ввод ограничен одним периодом (ну, вам не нужно использовать фиксированный период M_PI, вы можете пойти, допустим, к максимальному значению 3.5 и уменьшить ваши ответы для значений больше, просто уменьшив модуль деление на M_PI.

После того, как сказал это, мы можем связать максимальную ошибку, так как для наибольшего ввода 3.5 мы будем иметь 3.5^n/n! в качестве последнего члена нашего приближения, с ограничен для некоторых n быть меньше некоторого максимума ошибка, которая фиксирует количество терминов, которые нам нужно вычислить.

Вместо того, чтобы быть точным с количеством терминов, необходимых для расчета, я попытаюсь сделать некоторые догадки От вывода алгоритма и показаны фактические значения (например, для максимального значения входного сигнала 3.2)

Эти значения термина в положении n для ввода 3.2 и

n | term at position n for input `3.2` 
======+================= 
    8 | 0.27269634 
    12 | 0.00240693 
    16 | 0.00000578 
    18 | 0.00000019 
    20 | 0.00000001 
    21 | 7.9E-10 

Таким образом, мы можем остановка при вычислении всего 20 членов серии. Это верно для функции exp(), которая добавляет все термины и является простой функцией.Для sin() или cos() вы можете догадаться, что лучшая оценка погрешности, если учесть, что оба имеют одинаковые условия функции exp(), (ну первое имеет только нечетные член, то второй имеют только четные термины)

(x^n)/(n!) - (x^(n+2))/((n+2)!) = (n!*x^n*(1 - x^2/((n+1)*(n+2))))/n! 

что для n > 3.2 означает, что каждый член является

< x^n/n! 

так что мы можем применить тот же критерий, что и для экспоненциальной.

Это означает, что мы можем остановиться на какой-то момент ... если мы продолжим нашу таблицу, мы увидим, что при, например, n > 30 общий накопленный срок меньше 5.3E-18 так что мы можем там остановиться (для double числа , как минимум).

#include <stdio.h> 
#include <math.h> /* for the system sin() function */ 

double MySin(double x) /* x must be in the range [0..3.2] */ 
{ 
    int i; 
    const int n = 30; 
    double t = x, acum = x; /* first term, x/1! */ 
    x *= x; /* square the argument so we get x^2 in variable x */ 
    for (i = 3; i < n; i += 2) { 
      t = -t * x/i/(i-1); /* mutiply by -1, x^2 and divide by i and (i-1) */ 
      acum += t; /* and add it to the accum */ 
    } 
    return acum; 
} 

int main() 
{ 
    double arg; 
    for(;;) { 
      if (scanf("%lg", &arg) != 1) 
        break; 
      printf("MySin(%lg) = %lg; sin(%lg) = %lg\n", 
        arg, MySin(arg), arg, sin(arg)); 
    } 
} 

Если вы воспользоваться из симметрий, что функция греха, вы можете уменьшить свой домен M_PI/4, который меньше, чем один, и вы можете остановить даже при сроке власти 18, чтобы получить около 17 сигнификативных цифр (для double), что делает ваш грех быстрее.

Наконец, мы можем получить действительный для всех действительных функций домена sin2() по:

double sin2(double x) 
{ 
    bool neg = false; 
    int ip = x/2.0/M_PI; 
    x -= 2.0 * M_PI * ip;     /* reduce to first period [-2PI..2PI] */ 
    if (x < 0.0) x += 2.0*M_PI;    /* reduce to first period [0..2PI] */ 
    if (x > M_PI) { x -= M_PI; neg = true; } /* ... first period negative [ 0..PI ] */ 
    if (x > M_PI/2.0) x = M_PI - x;   /* reflection [0..PI/2] */ 
    return neg ? MySin(-x) : MySin(x); 
} 
Смежные вопросы