Деякі нюанси виведення графіків функцій, Різне, Програмування, статті

Автор: Олексій Легкунец, Королівство Delphi


Вивчаючи доступну літературу з програмування, яку я знайшов в Інтернеті, а також деякі програми, я прийшов до висновку, що програмісти чи то не усвідомлюють, то чи не хочуть напружуватися на цю тему, і все роблять, як у школі вчили. Будують графіки, як на папері. Тим самим зменшуючи можливості комп’ютера. Залишаючи ті ж недоліки методу побудови, і навіть збільшуючи їх.


По перше висновок на екран – це виведення на дискретний носій. Цей факт майже ніяк не враховується. В тексті буде пояснено.


А зараз я приведу приклад програми з одного навчального електронного видання, автора я привести не можу, тому що останній не вказаний.

unit Graf;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormPaint(Sender: TObject);
procedure FormResize(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
Function f(x:real):real;
begin
f:=2*Sin(x)*exp(x/5);
end; / / Будує графік функції
procedure GrOfFunc;
var x1, x2: real; / / межі зміни аргументу функції y1, y2: real; / / межі зміни значення функції x: real; / / аргумент функції y: real; / / значення функції в точці х dx: real; / / прирощення аргументу
l, b: integer; / / лівий нижній кут області виведення графіка w, h: integer; / / ширина і висота області виведення графіка mx, my: real; / / масштаб по осях X та Y x0, y0: integer; / / точка – початок координат begin / / область виведення графіка l: = 10; / / X – координата лівого верхнього кута b: = Form1.ClientHeight-20; / / У – координата лівого верхнього кута h: = Form1.ClientHeight-40; / / висота w: = Form1.Width-40; / / ширина x1: = 0; / / нижня межа діапазону аргументу x2: = 25; / / верхня межа діапазону аргументу dx: = 0.01; / / крок аргументу
/ / Знайдемо максимальне і мінімальне значення / / Функції на відрізку [x1, x2]
y1: = f (x1); / / мінімум y2: = f (x1); / / максимум
x:=x1;
repeat
y := f (x);
if y < y1 then y1:=y;
if y > y2 then y2:=y;
x:=x+dx; until (x >= x2); / / Обчислимо масштаб my: = h / abs (y2-y1); / / масштаб по осі Y mx: = w / abs (x2-x1); / / масштаб по осі X
x0:=1;
y0:=b-Abs(Round(y1*my)) ;
with form1.Canvas do begin / / осі
MoveTo(l,b);LineTo(l,b-h);
MoveTo(x0,y0);LineTo(x0+w,y0);
TextOut(l+5,b-h,FloatToStrF(y2,ffGeneral,6,3));
TextOut(l+5,b,FloatToStrF(y1,ffGeneral,6,3)); / / Побудова графіка
x:=x1; repeat
y:=f(x);
Pixels[x0+Round(x*mx),y0-Round(y*my)]:=clRed;
x:=x+dx;
until (x >= x2);
end;
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
GrOfFunc; end; / / Змінився розмір вікна програми
procedure TForm1.FormResize(Sender: TObject);
begin / / Очистити форму
form1.Canvas.FillRect(Rect(0,0,ClientWidth,ClientHeight)); / / Побудувати графік
GrOfFunc;
end;
end.

Програма добре виводить графіки, коли функція має як позитивні, так і негативні значення. Причому весь графік поміщається в зазначеному прямокутнику.


Тепер подивимося, а скільки обчислень значень функції робить програма? В даному випадку (25-0) / 0.01 = 2500. Для будь-якого прямокутника виводу. Чим був зумовлений вибір кроку dx? Швидше за все, безперервністю лінії графіка. Який, до речі, так і залишився переривчастим на деяких ділянках, там, де функція змінюється швидко. Борються з цим, зменшуючи dx, причому частіше радикально – відразу в 10, і навіть в 100 разів, доводячи до 0.0001; менше мені не доводилося зустрічати. А це 250000 обчислень функції. І графіки все одно переривчасті. Благо комп’ютери швидкі. Але от якщо обчислювати функцію, задану неявно, то графік буде будується повільніше. Виберемо прямокутник виведення 600 * 400. Таким чином по горизонталі ми можемо мати лише 600 значень. По осі У, відповідно, теж. Питання: куди йдуть інші 249400 результату обчислень? Частина йде на побудову вертикальних відрізків прямих, що з’єднують сусідні ординати, а левову частку інших поїдає Round. Ось тобі і дискретний висновок. Звідси випливає, що функцію потрібно вважати в 600 точках, а відрізки вертикальних прямих можна намалювати олівцем. І dx потрібно вибирати в нашому випадку (25-0) / 600 = 0,0416666. Графік вийде самий якісний, який тільки можливо отримати. Потім, немає необхідності обчислювати її значення двічі. Можна раз, запам’ятавши результат в масиві (Масив має розмір не більше дозволу монітора). В таких умовах швидкість виводу не змінюється.


По-друге, сам метод побудови (обчислення значень функції з кроком dx) працює як фільтр, відсікаючи високочастотні гармоніки, тобто я хочу сказати, що якщо до функції f (x) додати щось на зразок g (x) * sin ( 2 * pi / dx * x), то результат виведення буде плачевним. Цей елемент ніяк не змінить попередній графік. Хоча він може бути основним носієм інформації про функції. І вже звичайно дуже непросто вивести на екран графік дискретної функції (мається на увазі універсальними програмами загального користування, подібними наведеної). Якщо взяти f (x) = 2 * Sin (x) * exp (x / 5) + exp (x * x) * sin (2 * pi / dx * x), то дана програма другий доданок не помітить, хоча буде витрачати час на розрахунок f (x) = 2 * Sin (x) * exp (x / 5) * exp (x * x) * sin (2 * pi / dx * x). А в цьому випадку графік константи. Наведена програма, як я згадував, некоректно відобразить і його, але це ж навчальна програма. Тому претензій не висуваємо.


А от якщо взяти TAB MathGrapher 1.0 (поширена в Інтернеті) і просто ввести 5 * Sin (200 * pi * x), то ми отримаємо чистий нуль. Замість 5, зрозуміло, можна написати будь-яку функцію, та й замість Sin (200 * pi * x) будь-яку періодичну з кратною частотою, і програма видасть невірний графік.


Це, як я вже писав, витрати методу побудови. Як з цим боротися? Неефективний і не виправляє програму брати dx = 0.0037 або щось на зразок, тоді складно буде підібрати період і натякають автора (жарт). Очевидно, потрібно, щоб програма давала можливість розглядати функцію на невеликому відрізку, з dx = (х2-х1) / w (ширина виводу в пікселях). Тобто програма повинна автоматично змінювати крок зі зменшенням відрізка. Щось подібне я написав, в результаті можна графічним методом вирішувати запаморочливі трансцендентні рівняння з точністю 10E-7 і вище за лічені хвилини (х2, х1 потрібно вводити вручну). Тим, хто над подібним не замислювався, код в руки, а користувачам хотілося б порекомендувати: не беріть програми, які не змінюють крок. А то у відповідальних випадках можна отримати невірний графік і потрапити в скрутне становище.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*