Pers.narod.ru. Алгоритмы. Считаем определенные интегралы и выводим график |
Метод трапеций.
Суть метода - проведение прямой через значения функции на границах каждого интервала интегрирования. Приближенное значение интеграла на интервале [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-графикой? Информация здесь
гостевая; E-mail |