Вопрос или проблема
Наш профессор дал нам задание вычислить синус заданного числа с помощью ряда Тейлора, пока два последовательных члена не различаются менее чем на 10-6, но раз я новичок в компьютерных науках, я не совсем уверен, как поступить дальше. Я полагаю, что факториал вычисляется правильно.
Я ожидал, что вывод суммы будет совпадать с выводом sin(x) из встроенной библиотеки.
Например, для входного значения: 1.0, вывод суммы должен быть 0.841471, совпадая с результатом простого введения 1.0 в заранее подготовленную функцию, но его вывод составляет 0.158529.
#include <stdio.h>
#include <math.h>
int main()
{
int val = 0, neg;
long double sum = 0.0, x, prev = 0.0, curr, factorial = 1.0;
printf("Введите X:\n");
scanf("%Lf", &x);
curr = x;
while (fabs(curr - prev) >= 0.000001){
val++;
prev = curr;
factorial *= (2 * val) * (2 * val + 1);
curr = (pow(x, 2 * val + 1)) / factorial;
if (val % 2 == 1)
neg = -1;
else
neg = 1;
sum += neg * curr;
}
printf("ряд Тейлора sinx: %Lf\n", sum);
printf("математическая библиотека sinx: %lf\n", sin(x));
return 0;
}
Вы установили curr = x;
и не установили sum = x;
тоже.
Это очевидно, когда вы выводите операции:
#include <stdio.h>
#include <math.h>
int main(void)
{
int val = 0, neg;
long double sum = 0.0, x, prev = 0.0, curr, factorial = 1.0;
printf("Введите X:\n");
scanf("%Lf", &x);
curr = x;
while (fabsl(curr - prev) >= 0.000001)
{
val++;
prev = curr;
factorial *= (2 * val) * (2 * val + 1);
curr = (powl(x, 2 * val + 1)) / factorial;
if (val % 2 == 1)
neg = -1;
else
neg = 1;
sum += neg * curr;
printf("val = %2d: neg = %+2d; factorial = %12.0Lf; term = %15.9Le; "
"old = %15.9Le; new = %15.9Le\n",
val, neg, factorial, curr, prev, sum);
}
printf("ряд Тейлора sinx: %Lf\n", sum);
printf("математическая библиотека sinx: %Lf\n", sinl(x));
return 0;
}
что приводит к следующему:
Введите X:
1
val = 1: neg = -1; factorial = 6; term = 1.666666667e-01; old = 1.000000000e+00; new = -1.666666667e-01
val = 2: neg = +1; factorial = 120; term = 8.333333333e-03; old = 1.666666667e-01; new = -1.583333333e-01
val = 3: neg = -1; factorial = 5040; term = 1.984126984e-04; old = 8.333333333e-03; new = -1.585317460e-01
val = 4: neg = +1; factorial = 362880; term = 2.755731922e-06; old = 1.984126984e-04; new = -1.585289903e-01
val = 5: neg = -1; factorial = 39916800; term = 2.505210839e-08; old = 2.755731922e-06; new = -1.585290154e-01
val = 6: neg = +1; factorial = 6227020800; term = 1.605904384e-10; old = 2.505210839e-08; new = -1.585290152e-01
ряд Тейлора sinx: -0.158529
математическая библиотека sinx: 0.841471
Вывод первого вычисления показывает ошибку. Исправление заключается в том, чтобы установить sum
(а также curr
) в x
:
#include <stdio.h>
#include <math.h>
int main(void)
{
int val = 0, neg;
long double sum = 0.0, x, prev = 0.0, curr, factorial = 1.0;
printf("Введите X:\n");
scanf("%Lf", &x);
sum = curr = x;
while (fabsl(curr - prev) >= 0.000001)
{
val++;
prev = curr;
factorial *= (2 * val) * (2 * val + 1);
curr = (powl(x, 2 * val + 1)) / factorial;
if (val % 2 == 1)
neg = -1;
else
neg = 1;
sum += neg * curr;
printf("val = %2d: neg = %+2d; factorial = %12.0Lf; term = %15.9Le; "
"old = %15.9Le; new = %15.9Le\n",
val, neg, factorial, curr, prev, sum);
}
printf("ряд Тейлора sinx: %Lf\n", sum);
printf("математическая библиотека sinx: %Lf\n", sinl(x));
return 0;
}
Вывод:
Введите X:
1
val = 1: neg = -1; factorial = 6; term = 1.666666667e-01; old = 1.000000000e+00; new = 8.333333333e-01
val = 2: neg = +1; factorial = 120; term = 8.333333333e-03; old = 1.666666667e-01; new = 8.416666667e-01
val = 3: neg = -1; factorial = 5040; term = 1.984126984e-04; old = 8.333333333e-03; new = 8.414682540e-01
val = 4: neg = +1; factorial = 362880; term = 2.755731922e-06; old = 1.984126984e-04; new = 8.414710097e-01
val = 5: neg = -1; factorial = 39916800; term = 2.505210839e-08; old = 2.755731922e-06; new = 8.414709846e-01
val = 6: neg = +1; factorial = 6227020800; term = 1.605904384e-10; old = 2.505210839e-08; new = 8.414709848e-01
ряд Тейлора sinx: 0.841471
математическая библиотека sinx: 0.841471
Обратите внимание, что я использовал функции long double
fabsl()
, powl()
, sinl()
, чтобы соответствовать аргументам long double
(в обоих вариантах кода). Важно быть последовательным, хотя вычисление может использовать переменные и функции double
и выдавать тот же вывод.
Ответ или решение
Неправильный вывод при расчете синуса с использованием ряда Тейлора на языке C
При выполнении задания вашего преподавателя по вычислению синуса заданного числа с использованием ряда Тейлора в языке программирования C возникла ошибка. В результате неправильного кода вы получаете неверный результат. В этом ответе мы разберем проблему, проанализируем код и предложим решение.
Проблема
Ваш начальный код устанавливает переменную curr
равной x
. Это вызывает путаницу, так как синус в ряде Тейлора рассчитывается не только от начального значения, но и от дополнительных членов ряда. Первый член ряда Тейлора для функции синуса это просто x
. Без установки sum
равным x
, расчеты будут неверными, и вы получите результат, не соответствующий стандартной библиотечной функции sin(x).
Ваша текущая реализация могла выглядеть так:
curr = x;
while (fabs(curr - prev) >= 0.000001) {
// ...
}
Вы не инициализируете sum
этим значением x
, что приводит к тому, что расчеты будут смещены. Результат выглядит как 0.158529
, вместо ожидаемого 0.841471
для sin(1.0)
.
Решение
Чтобы исправить код, вам необходимо инициализировать как sum
, так и curr
значением x
и следить за корректным порядком операций в вашей программе. Вот исправленный пример кода:
#include <stdio.h>
#include <math.h>
int main(void) {
int val = 0, neg;
long double sum = 0.0, x, prev = 0.0, curr, factorial = 1.0;
printf("Введите X:\n");
scanf("%Lf", &x);
sum = curr = x; // Инициализация sum и curr значением x
while (fabsl(curr - prev) >= 0.000001) {
val++;
prev = curr;
factorial *= (2 * val) * (2 * val + 1); // Вычисление факториала
curr = (powl(x, 2 * val + 1)) / factorial; // Следующий член ряда
// Определение знака текущего члена
neg = (val % 2 == 0) ? 1 : -1;
sum += neg * curr; // Добавление элемента к сумме
// Для отслеживания промежуточных вычислений
printf("val = %2d: neg = %+2d; factorial = %12.0Lf; term = %15.9Le; old = %15.9Le; new = %15.9Le\n",
val, neg, factorial, curr, prev, sum);
}
printf("Синус по ряду Тейлора: %Lf\n", sum);
printf("Синус по библиотечному sin(): %Lf\n", sinl(x));
return 0;
}
Выводы и рекомендации
После внесения исправлений, вы получите корректный результат, который будет соответствовать значению синуса, предоставляемому стандартной библиотекой. Выполнение программы с входным значением 1.0
теперь даст правильный результат:
Синус по ряду Тейлора: 0.841471
Синус по библиотечному sin(): 0.841471
Обратите внимание на использование функций fabsl()
, powl()
и sinl()
, которые соответствуют типу long double
для обеспечения более высокой precision.
При работе с числовыми методами, такими как разложение в ряд Тейлора, важно тщательно следить за инициализацией переменных и порядком выполнения операций для избежания ошибок. Мы надеемся, что предоставленные рекомендации помогут вам успешно завершить задание.