Форум: "Основная";
Текущий архив: 2002.08.15;
Скачать: [xml.tar.bz2];
Внизцикл 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;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.007 c