Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.01 c
14-48281
ev
2002-07-20 18:24
2002.08.15
как объявить функцию в C?


14-48285
MadMarine
2002-07-21 18:30
2002.08.15
Delphi5 &WinXP


6-48236
Ron
2002-06-03 21:40
2002.08.15
WebBrowser


1-48087
SemFLY
2002-07-28 21:02
2002.08.15
Печать документа Word


4-48370
ATLANTIDO
2002-06-03 16:12
2002.08.15
priority





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский