Nickolay.info. Алгоритмы. Считаем определенные интегралы и выводим график

Метод трапеций.

Суть метода - проведение прямой через значения функции на границах каждого интервала интегрирования. Приближенное значение интеграла на интервале [xi,xi+h], где h - шаг по x, определяется по формуле h*(f(xi)+f(xi+h))/2+R, где R - априорная погрешность.

Метод Симпсона.

Подынтегральная функция заменяется полиномом 2-й степени - параболой, проходящей через точки xi,xi+1,xi+2. В этом случае на интервале [xi,xi+2h] получаем значение интеграла по формуле [f(xi)+4f(xi+1)+f(xi+2)]*h/3

Метод разложения функции в ряд (метод Гаусса с двумя узлами). В этих методах функция приближается полиномами различных степеней, но узлы для построения полиномов выбираются из условия обеспечения минимальной погрешности интегрирования. В методе Гаусса с 2 узлами интеграл на отрезке интегрирования ищется по формуле , где , ,

Поскольку точное значение искомого интеграла равно 0, оценим сравнительную погрешность методов, вычисляя ее по формуле

, где Jbi - значения интеграла, вычисленные при заданных bi= {0.5,0.8,1.2,1.5,2.2}

Полученные оценки погрешности

Метод трапеций                   0.066703

Метод Симпсона                  0.066618

Метод Гаусса                        0.00672363

Вывод: наиболее точные результаты дал метод Гаусса, что согласуется с теорией.

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

float f (float x) { //Функция, интеграл от которой берется
 return x*x*atan(x);
}

float Trap (float x0,float h,float x1) { //Метод трапеций
 float x,s;
 s=(f(x0)+f(x1))/2;
 for (x=x0+h; x<x1; x+=h) {
  s+=f(x);
 }
 return s*h;
}

float Simpson (float x0,float h,float x1) { //Метод Симпсона
 float x,s;
 int i,n;
 n=(x1-x0)/h;
 s=(f(x0)+f(x1))/2+2*f(x0+h/2);
 x=x0;
 for (i=0; i<n-1; i++) {
  x+=h;
  s+=(2*f(x+h/2)+f(x));
 }
 return s*h/3;
}

float Gauss (float x0,float h,float x1) { //Разложение в ряд
 float x,c,d,s;
 int n,i;
 c=h/sqrt(3);
 d=h-c;
 x=x0+d/2;
 s=0;
 n=(x1-x0)/h;
 for (i=0; i<n; i++) {
  s+=f(x);
  x+=c;
  s+=f(x);
  x+=d;
 }
 return s*h/2;
}

void Init (void) { //Открытие графики
 int gdriver = VGA, gmode=VGAHI, errorcode;
 registerbgidriver(EGAVGA_driver);
 initgraph(&gdriver, &gmode, "");
 errorcode = graphresult();
 if (errorcode != grOk) {
  printf("Graphics error: %s\n", grapherrormsg(errorcode));
  printf("Press any key to halt");
  getch();
  exit(1);
 }
}

#define DX 10    /* Отступы по */
#define DY 10    /* X и Y */
#define CEPS 1e-6 /* Точность для циклов с вещ. числами */

void GraphOfFun (float x0, float x1) {
//	График функции f(x)
//	x0,x1 - границы по x
//	Шаг по x выбирается, исходя из разрешения монитора
 int i,j,flag=0,i0,j0;
 float x,fx,fmin,fmax;
 char *str="00000.000";
 //Первый проход - выяснить верхнюю и нижнюю границы по Y
 x=x0;
 fmin=f(x0); fmax=f(x0);
 while (x<=x1+CEPS) {
  if (f(x)>fmax) fmax=f(x);
  else if (f(x)<fmin) fmin=f(x);
  x+=0.001;
 }

 if ((x0<0) && (x1>0)) {
  setcolor (RED);
  i=DX-x0*(getmaxx()-2*DX)/(x1-x0);
  line (i,DY-1,i,getmaxy()-DY+1);
 }
 if ((fmin<0) && (fmax>0)) {
  setcolor (RED);
  j=getmaxy()-(DY-fmin*(getmaxy()-2*DY)/(fmax-fmin));
  line (DX,j,getmaxx()-DX,j);
 }
 //Нарисовать обрамление
 setcolor (YELLOW);
 rectangle (DX-1, DY-1, getmaxx()-DX+1, getmaxy()-DY+1);
 gcvt (x0,3,str); outtextxy (DX,getmaxy()-DY+2,str);
 gcvt (x1,3,str);
 outtextxy (getmaxx()-DX-textwidth(str),getmaxy()-DY+2,str);
 settextstyle (DEFAULT_FONT, VERT_DIR, 1);
 settextjustify (LEFT_TEXT, BOTTOM_TEXT);
 gcvt (fmin,3,str); outtextxy (DX-2, getmaxy()-DY-2, str);
 settextjustify (LEFT_TEXT, TOP_TEXT);
 gcvt (fmax,3,str); outtextxy (DX-2, DY+2, str);
 setcolor (GREEN);
 //Второй проход - нарисовать график
 i=DX;
 while (i<=getmaxx()-DX) {
  //Пересчитать i на экране в координату x на плоскости
  x=x0+(i-DX)*(x1-x0)/(getmaxx()-2*DX);
  //Вычислить f(x)
  fx=f(x);
  //Пересчитать f в экранные координаты
  j=DY+(fx-fmin)*(getmaxy()-2*DY)/(fmax-fmin);
  j=getmaxy()-j; //"Перевернули" график
  putpixel (i,j,GREEN);
  if (flag==0) { flag=1; i0=i; j0=j; }
  if (j!=j0) line (i0,j0,i,j);
	//Соединили с пред. точкой, чтоб не было видимых разрывов
  i0=i; j0=j;
  i++;
 }
}

void main (void) {
 float r,eps;
 float b[5]={0.5,0.8,1.2,1.5,2.2};
 int i,ch;
 do {
  clrscr();
  printf ("\n Нажмите клавишу для выбора действия:");
  printf ("\n 1. Вычисление интеграла методом трапеций");
  printf ("\n 2. Вычисление интеграла методом Симпсона");
  printf ("\n 3. Вычисление интеграла разложением в ряд");
  printf ("\n 0. Выход из программы\n ");
  fflush(stdin);
  ch=getchar();
  switch (ch) {
   case '1':
   case '2':
   case '3':
    eps=0;
    for (i=0; i<5; i++) {
     if (ch=='1')
      r=Trap (-b[i],(2*b[i])/100,b[i]);
     else if (ch=='2')
      r=Simpson (-b[i],(2*b[i])/100,b[i]);
     else if (ch=='3')
      r=Gauss (-b[i],(2*b[i])/100,b[i]);
     eps+=r*r;
     printf ("\n Значение интеграла, вычисленное при b=%g равно %g",b[i],r);
    }
    eps=sqrt(eps);
    printf ("\n Eps=%g",eps);
    printf ("\n Нажмите любую клавишу для вывода графика...");
    fflush (stdin);
    getchar();
    Init();
    GraphOfFun (-b[2],b[2]);
    fflush (stdin);
    getchar();
    closegraph();
   break;
   case '0': clrscr; return;
   default: break;
  };
 } while (1);
}

 Архив ZIP с файлами, запускать .BAT (53 Кб)

Проблемы с DOS-графикой? Информация здесь

Рейтинг@Mail.ru

вверх гостевая; E-mail