Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.08.15;
Скачать: CL | DM;

Вниз

цикл for   Найти похожие ветки 

 
IKiller   (2002-07-31 19:20) [0]

Или я перегрелся или это произошло с моим компом...
Есть цикл
for i:=0 to 9 do
DoSmth;
Ставлю брэйкпоинт на DoSmth. Вначале i принимает значение 10(!), потом 9, пото 8, а потом выходит из цикла.... i - локальная интежеровская переменная, до этого не использовалась, в цикле не меняется... Дельфу перегружал, оптимизацию отключал - не помогает. Далее следует аналогичный цикл - все ОК... Если написать цикл от 0 до 10 - то принимает значения 11, 10, 9; если for i:=9 downto 0 do - то 246,247....
Что за лабуда???


 
PVOzerski   (2002-07-31 19:27) [1]

Всё-таки это оптимизация. Если Вы внутри цикла не через Debug, а из программы будете запрашивать значения счётчика, компилятор сгенерит уже более "правильный" код. Где-то такие фичи Delphi описывлись, только не помню, где.


 
DiamondShark   (2002-07-31 19:31) [2]

Параметр цикла в теле цикла не используется, а потому компилер вправе генерировать максимально эффективный код, не обращая внимания на смысл параметра.
В частности, может использовать регистр для счетчика, может менять направление счета (как правило от N до 0 код получается короче).
По правилам паскаля значение переменной цикла после окончания цикла не определено, поэтому компилятор может не утруждать себя сохранением параметра в реальной переменной (даже если i будет глобальной переменной).
Отсюда и кажущиеся чудеса.


 
IKiller   (2002-07-31 19:37) [3]

Дословно цикл цикл ищет определенное значение в массиве и имеет вид:
for i:=0 to 9 do
if RptInitialScale=aiScaleTags[i] then
begin
ComboBoxInitialScale.ItemIndex:=aiScaleTags[i];
break;
end;
т.е. i внутри запрашивается....


 
IKiller   (2002-07-31 19:42) [4]

Всем огромное пасибо, поборол...


 
proc   (2002-07-31 20:10) [5]

Интересно как?
Я вчера столкнулся с такой же ерундой. Решил путем выноса переменной из процедуры. А как у вас?


 
Anatoly Podgoretsky   (2002-07-31 21:01) [6]

Зачем бороться с хорошим?


 
Helg   (2002-07-31 21:42) [7]

Уменя в своё время был точно такой же глюк. А это глюк в чистом виде. Я тогда переписал вместо
for i:=1 to 10 do if Aray[i]>0 then
begin
...
end;
написал
for i:=1 to 10 do
begin
if aray[i]>0 then
begin
...
end;
end;

И все заработало!
Делфу тоже люди писали...


 
Jeer   (2002-07-31 23:04) [8]

Это не глюк, а особенность работы компилятора.
Несущественные для нашей семантики begin end компилятор воспринимает как отдельный блок и оптимизирует в его рамках.


 
nick_sniper   (2002-07-31 23:52) [9]

Код
for i:=1 to 10 do if Aray[i]>0 then
begin
...
end;

Компилятор обрабатывает следующим образом:
1.Устанавливает значение i = 10
2.Устанавливает позицию массива = 1
3.Обрабатывает элемент массива
4.Сдвигает позицию массива +1
5.Уменьшае i на единицу
6.Если i>0 переходит к шагу 3
При этом значения i и указателя массива хранятся в регистрах а не в стеке ! Шаг 6 тоже занимает только один так процессора. Т.е. при неоптимизированном коде должно было бы быть:
1. Сравнить i со значением 10
2. Если больше то выход
что занимало бы не менее двух тактов. В нашем же случае происходит проверка достиг ли регистр значения 0, что занимает 1 такт.

Выводы:
1. В данном случае за счет оптимизации достигается прирост производительности более чем в два раза. (Нет лишних обращений к стеку).
2. Несмотря на то, что при отладке значения i отличаются от запланированных (цикл идет в обратном порядке) всё же весь код будет работать правильно и массив будет обрабатываться в прямом порядке, хотя это и не видно в отладчике.
3. Такая оптимизация производится только в том случае, если никакие значения не зависят от значения i. Т.е. нет вызовов процедур, свойств обьектов и т.д. При этом цикл должен быть достаточно мал для помещения всех переменных в регистры.
4. Это не глюк Делфи - это его особенность пускай и не слишком разрекламированная.
5. Несмотря на Ваши сомнения Делфи будет делать правильно работающий код, несмотря на кажущуюся неправильность в отладчике. Если исправить на:
for i:=1 to 10 do
Label1.Caption := IntToStr(i);

компилятор сразу же уберет всю лишнюю оптимизацию, т.к. здась используется реальное значение i

Уф... Что-то я слишком многословен... Если сомневаетесь в оптимизаторе - нажмите Ctrl+Alt+C в отлачике и прогоните прогу в ассемблерных коммандах. В 100% случаев будет виноват не компилятор а программист :о)


 
DiamondShark   (2002-08-01 00:28) [10]

Да успокойтесь вы! Нет никакого глюка!

В окно CPU посмотреть религия не позволяет?

Внутри begin ... end параметр i, конечно же, не используется?
В качестве счетчика цикла используется один регистр, а для индекса -- другой.

вот:

for i := 1 to 10 do
if Arr[i] > 0 then
begin
writeln("aaa");
writeln("bbb");
end;


Смотрим окно CPU:

for i := 0 to 10 do
mov esi, $0000000b Это будет счетчик
mov ebx, $0040a600 А это индекс. Для начала -- адрес Arr
if Arr[i] > 0 then
cmp dword ptr [ebx], $00
jle Test + $43
writeln("aaa");
... вызов процедуры, не интересно
writeln("bbb");
... вызов процедуры, не интересно
end
add ebx, $04
for i := 0 to 10 do
dec esi
jnz Test + $0c


Any questions?

Кстати, у меня (D5, Build 5.62) заключение тела цикла в дополнительный begin ... end ( Helg (31.07.02 21:42)) машинного кода не изменило ни на бит.

А товарищей proc, Helg и прочих борцов и победителей я поздравляю: вам удалось побороть один из лучших оптимизирующих компиляторов и заставить его сгенерировать менее оптимальный код.


 
Deus   (2002-08-01 09:56) [11]

Проще всего бороться с подобным - снять галоку "оптимизация" в настойках компилятора.....


 
IKiller   (2002-08-02 12:35) [12]

Компилятор и оптимизатор действительно работает как надо (в данном случае). Ошибка была в моем коде. Правильно
for i:=0 to 9 do
if RptInitialScale=aiScaleTags[i] then
begin
ComboBoxInitialScale.ItemIndex:=i; {а не - aiScaleTags[i]}
break;
end;
Т.е. значение i использую явно - и компилятор убрал оптимизацию.
Так что...виноват сам :)



Страницы: 1 вся ветка

Текущий архив: 2002.08.15;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.02 c
3-47968
KMZ
2002-07-26 08:01
2002.08.15
ORA-04091- ошибка в ORACLE,кто решал такую проблему помогите пож.


1-48117
Mark J.
2002-08-04 14:24
2002.08.15
!


1-48064
НАИВый панк
2002-08-03 01:03
2002.08.15
как Дэлфи выделяет зарегистрированные слова (begin, end, function


4-48363
tretmike
2002-06-10 12:28
2002.08.15
Как опредилить имя файла приложения, зная хендл окна


14-48265
Sergo
2002-07-17 07:26
2002.08.15
Помехи