График рисуется неверно
При работе следующего кода почему-то получается неверный график:
procedure TForm1.Button1Click(Sender: TObject);
const
x1 = -10;
x2 = 10;
m = 50;
var
x0,y0, x_pos, line_pos: integer;
x,y: real;
begin
with Image1 do
begin
x0 := Width div 2;
y0 := Height div 2;
with Canvas do begin
Pen.Color := clBlack;
Pen.Width := 1;
MoveTo(0, y0);
LineTo(ClientWidth, y0);
MoveTo(x0, 0);
LineTo(x0,ClientHeight);
Pen.Color := clRed;
Pen.Width := 2;
x := x1;
S := Edit1.Text;
x_pos := 1;
while x_pos <= length(S) do begin // заменяет все "х" в строке
if S[x_pos] = 'x' then begin
delete(S, x_pos, 1);
insert('(' + floattostr(x) + ')', S, x_pos);
end;
x_pos := x_pos + 1;
end;
Calc(S, ans, ErrPos, Mess); //вычисляет значение строки. S - сама строка, ans - значение выражения, ErrPos - индекс ошибки, Mess - сообщение ошибки
if ErrPos > 0 then
Label2.Caption := Mess;
y := ans;
MoveTo(x0 + Trunc(x * m), y0 - Trunc(y * m));
LineTo(x0 + Trunc(x * m), y0 - Trunc(y * m));
while x < x2 do begin
x_pos := 1;
x := x + 0.01;
S := Edit1.Text;
while x_pos <= length(S) do begin
if S[x_pos] = 'x' then begin
delete(S, x_pos, 1);
insert('(' + floattostr(x) + ')', S, x_pos);
end;
x_pos := x_pos + 1;
end;
Calc(S, ans, ErrPos, Mess);
y := ans;
LineTo(x0 + Trunc(x * m), y0 - Trunc(y * m));
Вот, что получается в результате работы кода:
Это, конечно, похоже на sin(x), однако хотелось бы большего сходства. В чём ошибка?
*Дополнено. Код процедуры Calc:
var
ans : real;
S : string;
ErrPos : integer;
Mess : string;
procedure Calc(S: string;
var V: real;
var ErrPos: integer;
var ErrMess: string
);
const
EOT = #0;
type
Functions = (ABSOLUTE, SQUARE, TRUNCATE,
ROUNDING, SINUS, COSINUS, ARC,
LOG, EXPONENT, SQUAREROOT,
DUMMY
);
const
FirstFunc = ABSOLUTE;
LastFunc = SQUAREROOT;
FuncNames: array[Functions] of string[6] =
('ABS', 'SQR', 'TRUNC', 'ROUND',
'SIN', 'COS', 'ARCTAN', 'LN',
'EXP', 'SQRT', ''
);
var
i : integer;
Ch : char;
procedure Error(Message: string);
begin
if ErrPos = 0 then begin
ErrMess := Message;
ErrPos := i;
Ch := EOT;
end;
end;
procedure NextChar;
begin
if ErrPos <> 0 then
Ch := EOT
else
repeat
i := i + 1;
if i <= length(S) then
Ch := UpCase(S[i])
else
Ch := EOT;
until Ch <> ' ';
end;
procedure Number(var V: real);
var
NumStr : string; {Текст числа}
Err : integer; {Номер неверного символа}
procedure IntNumber;
begin
if not(Ch in ['0'..'9']) then
Error('Число начинается не с цифры');
while Ch in ['0'..'9'] do begin
NumStr := NumStr + Ch;
NextChar;
end;
end;
begin
NumStr := '';
IntNumber;
if Ch = '.' then begin
NumStr := NumStr + Ch;
NextChar;
IntNumber;
end;
if Ch = 'E' then begin
NumStr := NumStr + Ch;
NextChar;
if Ch in ['+','-'] then begin
NumStr := NumStr + Ch;
NextChar;
end;
IntNumber;
end;
Val(NumStr, V, Err);
if Err <> 0 then
Error('Ошибка в числе');
end;
procedure Name(var F: Functions);
var
NameStr : string;
begin
if Ch in ['A'..'Z'] then begin
NameStr := Ch;
NextChar;
end
else
Error('Ожидается буква');
while Ch in ['A'..'Z', '0'..'9'] do begin
NameStr := NameStr + Ch;
NextChar;
end;
F := FirstFunc;
while (F <= LastFunc) and (NameStr <> FuncNames[F]) do
F := succ(F);
if F = DUMMY then
Error('Неправильное имя функции');
end;
function Func(F: Functions; ans: real) : real;
begin
Func := ans;
case F of
ABSOLUTE : Func := abs(ans);
SQUARE : Func := sqr(ans);
TRUNCATE : Func := trunc(ans);
ROUNDING : Func := round(ans);
SINUS : Func := sin(ans);
COSINUS : Func := cos(ans);
ARC : Func := arctan(ans);
LOG :
if ans > 0 then
Func := ln(ans)
else
Error('Логарифм неположительного числа');
EXPONENT : Func := exp(ans);
SQUAREROOT :
if ans >= 0 then
Func := sqrt(ans)
else
Error('Корень из отрицательного числа');
end;
end;
procedure Expression(var V: real); forward;
procedure Multiplier(var V: real);
var
F : Functions;
begin
if Ch in ['0'..'9'] then
Number(V)
else if Ch in ['A'..'Z'] then begin
Name(F);
if Ch <> '(' then
Error('Ожидается ''(''')
else begin
NextChar;
Expression(V);
V := Func(F, V);
if Ch = ')' then
NextChar
else
Error('Ожидается '')''')
end
end
else if Ch = '(' then begin
NextChar;
Expression(V);
if Ch <> ')' then
Error('Ожидается '')''')
else
NextChar
end
else
Error('Ожидается число, функция или ''(''');
end;
procedure Addend(var V: real);
var
Op : char; {Знак операции}
X : real; {Значение операнда}
begin
Multiplier(V);
while Ch in ['*','/'] do begin
Op := Ch;
NextChar;
Multiplier(X);
if Op = '*' then
V := V * X
else if X <> 0 then
V := V / X
else
Error('Деление на ноль');
end;
end;
procedure Expression(var V: real);
var
Op : char;
X : real;
begin
Op := '+';
if Ch in ['+','-'] then begin
Op := Ch;
NextChar;
end;
Addend(V);
if Op = '-' then
V := -V;
while Ch in ['+','-'] do begin
Op := Ch;
NextChar;
Addend(X);
if Op = '+' then
V := V + X
else
V := V - X
end;
end;
begin
ErrPos := 0;
i := 0;
NextChar;
Expression(V);
if Ch <> EOT then
Error('Ожидается конец выражения');
end;
Ответы (1 шт):
Автор решения: Vlad Chapl
→ Ссылка
В режиме отладки ставим break point на любую из трех строк
Calc(S, ans, ErrPos, Mess);
y := ans;
LineTo(x0 + Trunc(x * m), y0 - Trunc(y * m));
и смотрим как меняется x0 + Trunc(x * m) и y0 - Trunc(y * m). По вашей задумке они должны плавно меняться (для этого можно пошагово выполнить несколько иттераций, отслеживая изменения значений переменных).
Коротко об отладке + Лекция: Отладка программ в среде Delphi