Помощь - Поиск - Пользователи - Календарь
Полная версия: Помогите с графической частью...
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Роман
Вычисление интеграла методом симпсона 3/8
Вот задание:
Исходные данные:
Число уравнений 3. y=a*x^3+b*x+c; y=a*sin(x+b)+c; y=a*ln|x+b|+c; Коэффициенты a, b, c вещественные числа задаются с клавиатуры. Пределы интегрирования – вещественные числа, лежащие в пределах от –1000 до 1000. Число интервалов разбиения не более 500.
Отобразить на экране в графическом режиме с учетом масштабирования процесс вычисления интеграла. Выдать на экран точное и приближенное значения интеграла, погрешность вычисления.
Вот я написал код программы. Все работает, строит графики, но во второй функции (синусоида) иногда, при некоторых коэффициентах сбивается масштабирование, причем сбивается по оси Y(выходит за пределы экрана). Подписи под осями тоже не всегда отображаются. И еще когда вводишь число разбиений разное, почему-то значение интеграла не меняется... Поэтому сделал фиксированное...
Вот собственно код:


program simps3_8;
uses crt,graph;
type
    funct = function (x:real):real;
var
   a,b,i,q,w,c,err,Ir:real;
   n:integer;
   j:char;
function f1(x:real):real;far;
begin
     f1:=q*x*x*x+w*x+c;
end;

function f2(x:real):real;far;
begin
     f2:=q*sin(x+w)+c;
end;

function f3(x:real):real;far;
begin
     f3:=q*ln(abs(x+w))+c;
end;

procedure Simps(f1:funct; a,b:real; var I:real);
var
   x,h,q,w,c:real;
   e,m,n:integer;
begin
     i:=0;
     x:=a;
     h:=(b-a)/n;
     I:=(3*h/8)*(f1(x)+f1(b));
     for e:=1 to n-1 do begin
        if (e mod 3=0) then
        m:=2 else m:=3;
        x:=x+h;
        I:=I+(3*h*m*f1(x)/8);
         end;
     end;

procedure out_grp(f1:funct;xmin,xmax,ymin,ymax:real);
var
     drv,mode:integer;
     mx,my:real;
     xx,yy:real;
     sx:real;
     dltx,dlty:integer;
     s:string;
begin
     drv:=VGA;
     mode:=VGAHi;
     initgraph(drv,mode,'');
     ymin:=ymin/10;
     if (xmin/xmax)>0.1 then dltx:=20 else dltx:=0;
     if (ymin/ymax)>0.1 then dlty:=20 else dlty:=0;
     mx:=500/(xmax-xmin);
     my:=400/(ymax-ymin);
     sx:=(xmax-xmin)/550;
     settextjustify(1,1);
     xx:=xmin;
     repeat
        setcolor(1);
        line(trunc(40+mx*(xx-xmin)+dltx),20,trunc(40+mx*(xx-xmin)+dltx),469);
        str(xx:4:2,s);
        setcolor(15);
        outtextxy(trunc(40+mx*(xx-xmin)+dltx),475,s);
        xx:=xx+50*sx;
     until (xx>(xmax+50*sx));
     yy:=ymin+(ymax-ymin)/10;
     repeat
        setcolor(1);
        line(41,trunc(470-my*(yy-ymin)-dlty),630,trunc(470-my*(yy-ymin)-dlty));
        str(yy:4:2,s);
        setcolor(15);
        outtextxy(20,trunc(470-my*(yy-ymin)-dlty),s);
        yy:=yy+(ymax-ymin)/10;
     until (yy>(ymax+(ymax-ymin)/10));
     line(40,0,40,480);
     line(0,470,640,470);
     line(40,0,38,10);
     line(40,0,42,10);
     line(640,470,630,472);
     line(640,470,630,468);
     xx:=xmin;
     repeat
        yy:=f1(xx);
        putpixel(trunc(40+mx*(xx-xmin)+dltx),trunc(470-my*(yy-ymin)-dlty),7);
        xx:=xx+sx;
     until (xx>xmax);
     outtextxy(300,10,' Press ESC to continue ');
     outtextxy(635,455,'X');
     outtextxy(20,10,'Y');
     repeat until (readkey=#27);
     closegraph;
end;

begin
     clrscr;
     writeln('Введите коэффициенты уравнения a,b,c');
     readln(q,w,c);
     writeln('Введите нижний и верхний пределы интегрирования');
     readln(a,b);
     if (a>1000) or (a<-1000) or (b>1000) or (b<-1000)  then begin
        writeln('Превышен допустимый предел, нажмите любую клавишу чтобы выйти');
        readkey;
        exit;
     end;
     n:=500;
     writeln('Выберите функцию:');
     writeln('Нажмите 1, чтобы выбрать функцию:',q:5:2,'*x^3+',w:5:2,'*x+',c:5:2);
     writeln(' Нажмите 2, чтобы выбрать функцию:',q:5:2,'*sin(x+',w:5:2,')+',c:5:2);
     writeln(' Нажмите 3, чтобы выбрать функцию:',q:5:2,'*ln|x+',w:5:2,'|+',c:5:2);
     j:=readkey;
     if(j=#49) then begin
        simps(f1,a,b,i);
        Ir:=(q*b*b*b*b/4+w*b*b/2+c*b)-(q*a*a*a*a/4+w*a*a/2+c*a);
        err:=abs(I-Ir)/I*100;
        out_grp(f1,a,b,f1(a),f1(b));
     end;
     if(j=#50) then begin
        simps(f2,a,b,i);
        Ir:=(c*b-q*cos(b+w))-(c*a-q*cos(a+w));
        err:=abs(I-Ir)/I*100;
        out_grp(f2,a,b,f2(a),f2(b));
     end;
     if(j=#51) then begin
        simps(f3,a,b,i);
        Ir:=(c*b-q*(b+w)+q*(b+w)*ln(b+w))-(c*a-q*(a+w)+q*(a+w)*ln(a+w));
        err:=abs(I-Ir)/I*100;
        out_grp(f3,a,b,f3(a),f3(b));
     end;
     writeln('Приближенное значение интеграла I=',i:15:11);
     writeln('Точное значение интеграла I=',Ir:15:11);
     writeln('error =',err:15:11,' %');
     writeln('Число интервалов: ',n);
     readkey;
end.


Простите что нету комментариев((( еще не успел....
Был бы очень признателен если хотя бы подредактировали только графическую часть. Т.е. процедуру out_grp; Т.к. я плохо там всё понимаю и писал её на примере другой программы.
Я часть с подсчетом интеграла мне понятна и вполне устраивает.
Роман
я уже почти разобрался.
Просьба к админам удалить что ли тему раз никому не интересноsad.gif
IUnknown
Кто тебе виноват, что ты все завязал на "магических константах", и чем разобраться, что к чему, проще переписать с нуля программу?

Для начала, я бы выводил подписи по оси OX с двух сторон, то есть, чередовал бы вывод сверху/снизу:
Нажмите для просмотра прикрепленного файла

     i := 1;
     repeat
        setcolor(blue);
        line(trunc(40+mx*(xx-xmin)+dltx),20,trunc(40+mx*(xx-xmin)+dltx),469);
        str(xx:4:2,s);
        setcolor(white);
        if odd(i) then
           outtextxy(trunc(40+mx*(xx-xmin)+dltx),475,s)
        else
           outtextxy(trunc(40+mx*(xx-xmin)+dltx),455,s);
        inc(i);
        xx:=xx+50*sx;
     until (xx>(xmax+50*sx));
+ надо будет поднять само изображение абсциссы и стрелочку.

Во-вторых, неплохо было бы привести коэффициенты (входные данные), на которых происходит то, о чем ты говоришь. А не заставлять тех, кто зашел в тему и решил помочь, подбирать это вручную. Ты этого не сделал - вопрос остался без ответа... Это не значит, что тема никому не интересна. Это значит, что неинтересно делать то, чего можно было бы в принципе не делать - если бы вопрос был поставлен правильно.
Роман
Цитата(IUnknown @ 24.05.2011 14:50) *

Во-вторых, неплохо было бы привести коэффициенты (входные данные), на которых происходит то, о чем ты говоришь. А не заставлять тех, кто зашел в тему и решил помочь, подбирать это вручную. Ты этого не сделал - вопрос остался без ответа... Это не значит, что тема никому не интересна. Это значит, что неинтересно делать то, чего можно было бы в принципе не делать - если бы вопрос был поставлен правильно.

допустим a=30 b=1 c=30
Роман


procedure out_grp(f1:funct;xmin,xmax,ymin,ymax:real);
var
     drv,mode:integer;
     mx,my:real;
     xx,yy:real;
     sx:real;
     dltx,dlty,midx,midy:integer;
     s:string;
begin
     drv:=VGA;
     mode:=VGAHi;
     initgraph(drv,mode,'');
     SetLineStyle(SolidLn,0,ThickWidth);
     rectangle(0,0,getmaxx,getmaxy);   {рамка вокруг графика}
     if abs(xmin/xmax)<0.1 then dltx:=10 else dltx:=0;
     if (abs(xmin/xmax)<0.1) and (xmin<0) then dltx:=-10 else dltx:=0;
     ymin:=ymin/10;    {хз зачем, но так лучше 0_0}
     midx:=getmaxx div 2;   
     midy:=getmaxy div 2;
     mx:=(midx/4)/(xmax-xmin);   {типо масштабирование}
     my:=(midy/10)/(ymax-ymin);   {типо масштабирование}
     sx:=(xmax-xmin)/getmaxx;
     settextjustify(CenterText,CenterText);
     xx:=xmin;
     SetLineStyle(SolidLn,0,NormWidth);
     line(midx,0,midx,getmaxy); {ось y}
     line(0,midy,getmaxx,midy); {ось x}
     line(midx,0,midx-10,10);   {стрелочка на оси y}
     line(midx,0,midx+10,10);
     line(getmaxx,midy,getmaxx-10,midy+10); {стрелочка на оси x}
     line(getmaxx,midy,getmaxx-10,midy-10);
     xx:=xmin;
     str(xx:4:2,s);
     yy:=f1(xx);
     outtextxy(trunc(midx+mx*xx+dltx),midy+10,s);
     SetLineStyle(CenterLn,0,NormWidth);
     line(trunc(midx+mx*xx+dltx),midy,trunc(midx+mx*xx+dltx),trunc(midy-my*yy)); {пунктирная линия предела}
     MoveTo(trunc(midx+mx*xx+dltx),trunc(midy-my*yy));
     SetLineStyle(SolidLn,0,NormWidth);
     repeat     {вывод графика}
       yy:=f1(xx);
        LineTo(trunc(midx+mx*xx+dltx),trunc(midy-my*yy));
        xx:=xx+sx;
        MoveTo(trunc(midx+mx*xx+dltx),trunc(midy-my*yy));
     until (xx>xmax);
     str(xx:4:2,s);
     SetLineStyle(CenterLn,0,NormWidth);
     line(trunc(midx+mx*xx+dltx),midy,trunc(midx+mx*xx+dltx),trunc(midy-my*yy));  {пунктирная линия предела}
     outtextxy(trunc(midx+mx*xx+dltx),midy+10,s);
     outtextxy(trunc(midx/2),10,' Press ESC to continue ');
     outtextxy(630,220,'X');
     outtextxy(300,10,'Y');
     outtextxy(330,230,'0');
     repeat until (readkey=#27);
     closegraph;
end;


вот подправил чуть чуть... Решил сделать без сетки + подписи только на концах интервала
Пожалуйста помогите как сделать чтобы график автоматически растягивался или сужался по осям, чтобы не выходил за пределы осей, помогите плиз, я пытался сделать но всеравно криво получаетсяsad.gif(((
Роман
Все всем спасибо, переписал с нуля графическую часть, вопрос решен, все правильно строит при любых коэффициентах.
P.S удалите тему а то палевоsmile.gif курсач как бы) хотя как хотите)
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.