С серией Тейлора вы можете довольно близко подойти.Хитрость заключается не в том, чтобы рассчитать полный факториал на каждой итерации.
Ряд Тейлора выглядит следующим образом:
sin(x) = x^1/1! - x^3/3! + x^5/5! - x^7/7!
Глядя на термины, вы вычисляете следующий член, умножая числитель наx ^ 2, умножая знаменатель на следующие два числа в факториале и меняя знак.Затем вы останавливаетесь, когда добавление следующего термина не меняет результат.
Таким образом, вы можете закодировать его так:
double double_sin(double x)
{
double result = 0;
double factor = x;
int i;
for (i=2; result+factor!=result; i+=2) {
result += factor;
factor *= -(x*x)/(i*(i+1));
}
return result;
}
Мой вывод:
0.1296341426196949
0.1296341426196949
-0.0000000000000000
РЕДАКТИРОВАТЬ:
Точность может быть дополнительно увеличена, если термины добавляются в обратном направлении, однако это означает вычисление фиксированного количества терминов:
#define FACTORS 30
double double_sin(double x)
{
double result = 0;
double factor = x;
int i, j;
double factors[FACTORS];
for (i=2, j=0; j<FACTORS; i+=2, j++) {
factors[j] = factor;
factor *= -(x*x)/(i*(i+1));
}
for (j=FACTORS-1;j>=0;j--) {
result += factors[j];
}
return result;
}
Эта реализация теряет точность, если x
выходит за пределы диапазона от 0 до 2 * PI.Это можно исправить, вызвав x = fmod(x, 2*M_PI);
в начале функции для нормализации значения.