Ошибка округления в программе интеграции c

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

Его результат: 0,189070
мой результат: 0,189053

я пытался пройти и бросить почти все, что я могу придумать, но все еще не могу понять, откуда я получаю свою ошибку, любая помощь в указании того, где я идиот, будет очень признательна! :п

Моя программа:

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

#define debug 0
#define N (double)10000

double Integrand(double x, int a, int n);
double Integral(double *x, double dx, int a, int n);

int main (int argc, char* argv[])
{
    int j,a,n=0,count=0,size=(int)N;
    double dx=1/N, x[size];

    sscanf(argv[1], "%d", &a);
    for(j=0;j<N;j++) {
        x[j]=(double)(j)*dx;
    }
    for(n=1;n<=10;n++) {
        printf("n is %d integral is %lf\n",n,Integral(x,dx,a,n));
    }    
    return(EXIT_SUCCESS);
}

double Integral(double *x, double dx, int a, int n)
{
    int i;
    double result=0;

    for(i=0;i<N;i++) {
       result +=(double)((Integrand((double)x[i],a,n))*dx);
    }
    return(result);
}

double Integrand(double x, int a, int n)
{
   double result;
   result=(double)(((pow(x,(double)n))/(x+(double)a)));
   return(result);
}

person user1831711    schedule 01.12.2012    source источник
comment
Вы используете ту же платформу компиляции? Вы читали stackoverflow.com/q/13571073/139746?   -  person Pascal Cuoq    schedule 01.12.2012
comment
Код ваших друзей идентичен вашему?   -  person mathematician1975    schedule 01.12.2012
comment
вместо использования dx = 1/N в прямом расчете 1/N. Я думаю, что когда вы берете значение 1/N в dx, происходит некоторая потеря точности. и это распространяется.   -  person Debobroto Das    schedule 01.12.2012
comment
«я пытался просмотреть и преобразовать почти все, что я мог придумать» … и вы усвоили ценный урок: преобразование всего, что вы можете придумать, не устраняет проблемы, и это делает программу ужасной.   -  person Pascal Cuoq    schedule 01.12.2012


Ответы (2)


Это не ошибка округления, вы просто не выбираете лучший выбор для точек интегрирования. Измените инициализацию на

x[j]=(j+0.5)*dx;

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

Если вы аппроксимируете интеграл достаточно гладкой функции f суммой Римана,

 b           n
 ∫ f(x) dx ≈ ∑ f(y_k)*(b-a)/n
 a          k=1

выбор y_k в интервале [x_(k-1), x_k] = [a+(k-1)*(b-a)/n, a+k*(b-a)/n] влияет на ошибку и скорость сходимости. Пишу

f(x) = f(y_k) + f'(y_k)*(x-y_k) + 1/2*f''(y_k)*(x-y_k)² + O((x-y_k)³)

в этом интервале вы обнаружите, что

x_k                                   x_k                            x_k
 ∫ f(x) dx = f(y_k)*(b-a)/n + f'(y_k)* ∫ (x-y_k) dx + 1/2*f''(y_k) * ∫ (x-y_k)² dx + O(1/n^4)
x_(k-1)                               x_(k-1)                       x_(k-1)

           = f(y_k)*(b-a)/n + 1/2*f'(y_k)*(b-a)/n*((x_k-y_k)-(y_k-x_(k-1))) + O(1/n³)

и первый и самый большой член ошибки относительно приближения f(y_k)*(b-a)/n обращается в нуль для

y_k = (x_k + x_(k-1))/2

что дает вам общую ошибку O (1 / n³) для этой полосы и общую ошибку O (1 / n²) для всей суммы Римана.

Если вы выберете y_k = x_(k-1) (или y_k = x_k), первый член ошибки станет

±1/2*f'(y_k)*[(b-a)/n]²

что приводит к общей ошибке O(1/n).

person Daniel Fischer    schedule 01.12.2012
comment
У вас есть инструмент для создания отформатированных уравнений, которые вы вставили туда, или это ручная работа? - person Jonas Schäfer; 01.12.2012
comment
@JonasWielicki Вся ручная работа. Например, я набираю имя объекта HTML &sum;, копирую отображаемый глиф и вставляю его в блоки кода. (Боже, как бы я хотел, чтобы этот сайт поддерживал рендеринг LaTeX.) - person Daniel Fischer; 01.12.2012
comment
Спасибо за объяснение, теперь я чувствую себя немного идиотом, поскольку я должен был понять, что сам, насколько я помню, пару лет назад в колледже выполнял суммы Реймана между средней и конечной точками, теперь, когда вы это сказали. - person user1831711; 01.12.2012
comment
@user1831711 user1831711 Если бы забывание чего-то выученного делало человека идиотом, я бы боролся за титул чемпиона мира. Теперь вы прошли переподготовку, так что следующие пару лет вы будете помнить. - person Daniel Fischer; 01.12.2012
comment
@user1831711 user1831711 Примите его ответ, чтобы поблагодарить его за обновление;) - person Jonas Schäfer; 01.12.2012

В командной строке терминала Linux введите:

man fegetenv
person Eric    schedule 01.12.2012
comment
В большинстве операционных систем указано, что новые процессы запускаются с округлением до ближайшего. Я полагаю, что в IEEE 754 даже есть рекомендация на этот счет. - person Pascal Cuoq; 01.12.2012