Ключевой момент:
TERMS
слишком мал для правильной точности. И если вы увеличите TERMS
, вам придется изменить реализацию fact
, так как она, вероятно, будет переполнена при работе с int
.
. Я бы использовал знак для переключения мощности -1 вместо pow(-1,n)
overkill.
Затем используйте double
для значения PI, чтобы избежать потери слишком большого числа десятичных знаков
Затем для больших значений вам следует увеличить количество членов (это основная проблема). используя long long
для вашего факториального метода или вы получите переполнение. Я установил 10 и получил правильные результаты:
#include <stdio.h>
#include <math.h>
const int TERMS = 10;
const double PI = 3.14159265358979;
long long fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double powd(double x,int n) {
return n<= 0 ? 1 : x * powd(x,n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += sign * powd(rad, (2 * n) + 1)/ fact((2 * n) + 1);
sign = -sign;
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += sign * powd(rad, 2 * n) / fact(2 * n);
sign = -sign;
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
результат:
240
sine(240)= -0.866026
cosine(240)= -0.500001
Примечания:
- моя рекурсивная реализация
pow
с использованием последовательных умноженийвероятно, не нужно, так как мы имеем дело с плавающей точкой. Он вводит ошибку накопления, если n большое. fact
может использовать плавающую точку, чтобы обеспечить большее число и лучшую точность. На самом деле я предложил long long
, но было бы лучше не предполагать, что размера будет достаточно. Для этого лучше использовать стандартный тип, например int64_t
. fact
и pow
результаты также могут быть предварительно вычислены / жестко закодированы. Это сэкономит время вычислений.