Синусоидальная функция с использованием расширения Тейлора (Программирование на C) - PullRequest
3 голосов
/ 27 декабря 2011

Здесь - это вопрос ..

Это то, что я сделал до сих пор,

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

long int factorial(int m)
{
    if (m==0 || m==1) return (1);
    else      return (m*factorial(m-1));
}
double power(double x,int n)
{
    double val=1;
    int i;
    for (i=1;i<=n;i++)
    {
        val*=x;
    }
    return val;
}

double sine(double x)
{
    int n;
    double val=0;
    for (n=0;n<8;n++)
    {
        double p = power(-1,n);
        double px = power(x,2*n+1);
        long fac = factorial(2*n+1);
        val += p * px / fac;
    }
    return val;
}

int main()
{
    double x;
    printf("Enter angles in degrees: ");
    scanf("%lf",&x);
    printf("\nValue of sine of %.2f is %.2lf\n",x,sine(x * M_PI / 180));
    printf("\nValue of sine of %.2f from library function is %.2lf\n",x,sin(x * M_PI / 180));
    return 0;
}

Проблема в том, что программа прекрасно работает изОт 0 до 180 градусов, но кроме того, это дает ошибку. Также, когда я увеличиваю значение n в for (n=0;n<8;n++) выше 8, я получаю значительную ошибку. В алгоритме нет ничего плохого, я проверил его вмой калькулятор, и программа, кажется, тоже хорошо .. Я думаю, что проблема связана с диапазоном типа данных .. что я должен исправить, чтобы избавиться от этой ошибки?
Спасибо ..

Ответы [ 5 ]

2 голосов
/ 27 декабря 2011

Вы правы, что ошибка связана с диапазоном типа данных.В sine () вы вычисляете факториал 15, что является огромным числом и не умещается в 32 бита (что, вероятно, и то, что long int реализовано как в вашей системе).Чтобы исправить это, вы можете:

  1. Переопределить факториал, чтобы получить двойное значение.
  2. Переработать код, чтобы объединить мощность и факториал в один цикл, который поочередно умножается на x и делитя.Это будет выглядеть беспорядочно, но позволит избежать возможности переполнения двойного числа (предоставлено, я не думаю, что это проблема для вашего варианта использования).
2 голосов
/ 27 декабря 2011

15! действительно вне диапазона, который может содержать 32-битное целое число. Я бы использовал двойные повсюду на вашем месте.

Ряд Тейлора для sin(x) сходится медленнее при больших значениях x. Для x снаружи - & pi;, & pi ;. Я бы добавил / вычел кратные 2 * & pi; чтобы получить как можно меньше х.

0 голосов
/ 07 января 2014

Вам нужно уменьшение диапазона. Обратите внимание, что ряд Тейлора лучше всего близок к нулю и что в отрицательном диапазоне это (отрицательное) зеркальное отражение его положительного диапазона. Итак, вкратце: уменьшите диапазон (по модулю 2 PI), чтобы обернуть его в диапазон, где у вас самая высокая точность. Диапазон за пределами 1/2 PI становится менее точным, поэтому вы также хотите использовать формулу: sin (1/2 PI + x) = sin (1/2 PI - x). Для отрицательных значений используйте формулу: sin (-x) = -sin (x). Теперь вам нужно только оценить интервал 0 - 1/2 PI, охватывая весь диапазон. Конечно, для ОЧЕНЬ больших значений пострадает точность модуля 2 PI.

0 голосов
/ 27 декабря 2011

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

Дело в том, что вам нужно написать функцию только для 0 <= x <= \ pi; все другие значения будут следовать с использованием этих отношений: </p>

  sin(-x) = -sin(x)

и

sin(x+\pi;) = -sin(x)

и

sin(x+2n\pi) = sin(x)

Я бы порекомендовал вам нормализовать входной угол, используя их, чтобы ваша функция работала для всех углов, как написано.

В вашем коде много неэффективности (например, вы продолжаете пересчитывать факториалы, которые легко поместились бы при поиске в таблице; вы используете power () для колебания между -1 и +1). Но сначала сделайте так, чтобы он работал правильно, а затем быстрее.

0 голосов
/ 27 декабря 2011

У вас могут возникнуть проблемы с 15!

...