Есть у нас на форуме такая рубрика "Приколы от админа". Но вот решил один из приколов выложить в новостях. Дальше приведена простенькая программка на Паскале. Компилируется без проблем, все правильно по синтаксису. Но не работает... Попробуйте найти ответ - почему? Аналогичные задачки можно найти на нашем форуме. (Эта программка когда-то попала в мою коллекцию с какого-то сайта). Высказывайтесь!
var x1,y1,x2,y2,dx,dy:integer;
d:real;
begin
x2:=520;y2:=200;
x1:=320;y1:=200;
dx:=x2-x1;
dy:=y2-y1;
d:=dx*dx+dy*dy;{???}
d:=sqrt(d);{!!!}
end.
2008-10-18 • Просмотров [ 22345 ]
d:real;
q;=char;
begin
x2:=520;y2:=200;
x1:=320;y1:=200;
dx:=x2-x1;
dy:=y2-y1;
d:=dx*dx+dy*dy;{???};
d:=sqrt(d);{!!!};
writeln(q
)
end.
Решил проверить насколько дал реальные советы по реальному типу:
"2")оказалось, что локальное приведение типа integer->real в TurboPascal
не работает (в моей голове это глюк- из MatLab'а, др.языков
и общей идеологии компиляции арифметических выражений со смешанными, но совместимыми, типами данных).
"1")с промежуточными переменными- всё в порядке
(как собственно написал ещё вчера Anton Golub (DoVe)):
добавим в начале:
function test(dx,dy: Real): Real;
Begin
test := dx*dx+dy*dy;
End;
и встроим строчку с вызовом:
dy:=y2-y1;
d:= test(dx,dy); {!}
d:= dx*dx+dy*dy;{???}
+)Пример "не сработает" если компилировать с ключами {$Q+,R+}.
До вычисления кв.корня появится ошибка переполнения.
По-видимому, они (ключи) были у Вас сброшены.
Не забывайте и о TurboDebagger'е, он проявит все детали.
При {$Q-,R+}:
PROGRAM.16: d:= dx*dx+dy*dy;{???}
cs:00D1>A15A00 mov ax,[PROGRAM.DY]
cs:00D4 F7265A00 mul word ptr [PROGRAM.DY]
cs:00D8 8BC8 mov cx,ax
cs:00DA A15800 mov ax,[PROGRAM.DX]
cs:00DD F7265800 mul word ptr [PROGRAM.DX]
cs:00E1 03C1 add ax,cx
cs:00E3 99 cwd
cs:00E4 9A3636CC67 call 67CC:3636 ; преобразование к real
cs:00E9 A35C00 mov [PROGRAM.D],ax
cs:00EC 891E5E00 mov [005E],bx
cs:00F0 89166000 mov [0060],dx
PROGRAM.18: d:=sqrt(d);{!!!}
При {$Q+,R+}:
PROGRAM.16: d:= dx*dx+dy*dy;{???}
cs:00DF>A15A00 mov ax,[PROGRAM.DY]
cs:00E2 F72E5A00 imul word ptr [PROGRAM.DY]
cs:00E6 7105 jno 00ED
cs:00E8 9AC702CE67 call 67CE:02C7 ; уход на вопли №215
cs:00ED 8BC8 mov cx,ax
cs:00EF A15800 mov ax,[PROGRAM.DX]
cs:00F2 F72E5800 imul word ptr [PROGRAM.DX]
cs:00F6 7105 jno 00FD
cs:00F8 9AC702CE67 call 67CE:02C7
cs:00FD 03C1 add ax,cx
cs:00FF 7105 jno 0106
cs:0101 9AC702CE67 call 67CE:02C7
cs:0106 99 cwd
cs:0107 9A3636CE67 call 67CE:3636
cs:010C A35C00 mov [PROGRAM.D],ax
cs:010F 891E5E00 mov [005E],bx
cs:0113 89166000 mov [0060],dx
PROGRAM.18: d:=sqrt(d);{!!!}
Паскаль хотя и относится (номинально) к учебным языкам требует
осторожности и чёткого осознания - чего и как программист хочет сделать
(т.е. предполагает скорее профессионального программиста).
(Иначе получается GIGO - "Garbage In Garbage Out").
Пока.
по идее компилятор должен был бы посмотреть на тип приёмника (real)
и производить все действия "поднимая" типы промежуточных рез-тов
до него,
на деле же TurboPascal работает с локальным (только для текущей операции) подъёмом типа,
т.е. если бы переменная dy была объявлена extended, то вычисление dy*dy (=0) произошло бы в формате extended,
далее сложение с результатом dx*dx - в нём же
(результат столь же неправильный).
В данном примере, если требуется, чтобы dx была объявлена integer,
то надо использовать: либо промежуточные ячеёки типа real
(и умножать их),
либо локальное приведение типа: d:=real(dx)*dx+real(dy)*dy;
Всё. Удачи!