USBLexus
Опытный
Offline
Пол:
Кот рыжий
|
|
« : 08-11-2005 05:02 » |
|
Правда ли что сравнение с нулем эффективнее чем с числом? Т.е. цикл будет работать быстрее for(int i=100; i; --i;)
чем этот цикл for(int i=0; i<100; ++i;)
|
|
|
Записан
|
#define QUESTION(b) (2*b)||(!(2*b)) (c) William Shakespeare
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 08-11-2005 05:23 » |
|
думаю разницы в случае не ассемблера нет а может быть и в случае асма тоже. (кстати - перед скобкой в конце не надо семиколон) смотри: 158: for(int i=100; i; --i) 00442D51 mov dword ptr [ebp-14h],64h 00442D58 jmp CGuard2View::CGuard2View+3F3h (00442d63) 00442D5A mov ecx,dword ptr [ebp-14h] 00442D5D sub ecx,1 00442D60 mov dword ptr [ebp-14h],ecx 00442D63 cmp dword ptr [ebp-14h],0 00442D67 je CGuard2View::CGuard2View+41Ch (00442d8c)
160: //÷åì ýòîò öèêë 161: for(int i=0; i<100; ++i) 00442D69 mov dword ptr [i],0 00442D70 jmp CGuard2View::CGuard2View+40Bh (00442d7b) 00442D72 mov edx,dword ptr [i] 00442D75 add edx,1 00442D78 mov dword ptr [i],edx 00442D7B cmp dword ptr [i],64h 00442D7F jge CGuard2View::CGuard2View+41Ah (00442d8a)
код - "одинаковый по времени"
|
|
|
Записан
|
|
|
|
Hooter
|
|
« Ответ #2 : 08-11-2005 05:44 » |
|
Правда ли что сравнение с нулем эффективнее чем с числом? Т.е. цикл будет работать быстрее
Теоретически, да. А практически, чтобы увидеть разницу, нужно как минимум отключить оптимизацию при компиляции.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #3 : 08-11-2005 05:50 » |
|
USBLexus , замерь время: DWORD time1; DWORD time2; DWORD diftime;
time1=GetTickCount();
//... тут - то, где надо измерить время
time2=GetTickCount(); diftime=time2-time1;
//diftime - время в миллисекундах
|
|
|
Записан
|
|
|
|
USBLexus
Опытный
Offline
Пол:
Кот рыжий
|
|
« Ответ #4 : 08-11-2005 09:09 » |
|
Проверял на таком вот коде:
DWORD time1; DWORD time2; DWORD diftime1; DWORD diftime2; int temp=0;
while(1){
time1=GetTickCount();
for(DWORD i=100000; i; --i) for(DWORD k=5000; k; --k) temp=7; time2=GetTickCount();
diftime1=time2-time1;
time1=GetTickCount();
for(DWORD i=0; i<100000; ++i) for(DWORD k=0; k<5000; ++k) temp=7;
time2=GetTickCount();
diftime2=time2-time1; } Разницы вроде никакой, даже если она и есть то очень маленькая
|
|
|
Записан
|
#define QUESTION(b) (2*b)||(!(2*b)) (c) William Shakespeare
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 08-11-2005 09:52 » |
|
да эта маленькая разница скорее всего из-за других работающих программ. Код одинаковый, теоретически разницы нет
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #6 : 08-11-2005 17:13 » |
|
Это смотря как компилятор строит цикл. 1. Он может загнать переменную в регистр CX (eCX) и делать цикл через команду LOOP. Тогда разница должна проявлятся.
2. Осушествлять проверку на нуль через команду CMP AX,0 (заместо регистра может быть ячейка памяти) JNZ ...... Если этим способом, то не должно быть вообше разници
3. Делать проверку сразу после декременирования DEC AX (или ячейка памяти) JNZ ...... Но этот вариант очень маловероятен по логике построения комманд компилятором.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #7 : 08-11-2005 17:22 » |
|
хороший компилятор при декременте должен бы воспользоваться командой loop, которая чуть быстрее, чем сравнение и прыжок. увеличение скорости должно быть, хоть и небольшое. но у меня были тупые ошибки из-за этого счета наоборот. а геттиккаунт - штука очень не точная (сталкивался с этим).
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #8 : 08-11-2005 17:31 » |
|
Алик, LOOP сам декриментирует. Поэтому это самый быстрый будет способ посторения цикла. Но есть одно но. Занимается регистр. Что не есть хорошо для логики компилятора
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #9 : 09-11-2005 09:18 » |
|
Тут опять же все упирается в качество самого компилятора. Хорошему занятый регистр не помешает. хороший старается оптимизировать как-то циклы и вполне может как-то извратиться, чтобы для возрастающего цикла loop использовать.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #10 : 09-11-2005 13:12 » |
|
Может быть. Только я один раз долго ловил блох, когда компилятор переделал с возрастаюшего цикла в ниспадаюший. Не помню какая была задача. Но мне очень важно было, чтобы массив заполнялся по возрастанию. Второй раз, когда я столкнулся с багами связанными с оптимизацией совсем недавно. В Debug режиме программа работала просто на ура. В Release режиме она падала с треском. Я так и не разобрался почему. Так что оптимизация, оптимизации рознь. Когда делаеш программу на уровне косвенных эффектов, иногда можно получить кучу багов во время компиляции в разных режимах.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
acc15
Гость
|
|
« Ответ #11 : 13-12-2005 06:06 » |
|
вы никак не отловите время выполнения 1-2 команд... gettickcount - бред, оссобенно в многозадачной ос, оссобенно в современных процах, там и предвыборка и предугадывание перехода. Исходя из справочников выполнение команд: cmp --- в зависимости от данных 1/2 или 1 такт jmp --- R-режим = 1 такт. P-режим = 3 такта. loop --- R-режим = 2 такта. P-режим = 6 тактов. где R - реальный режим, а P - страничный режим (Windows) странно но что-то тут нето... loop = dec ecx, cmp ecx,0 jnz loopmet (dec ecx = 1) + (cmp ecx,0 = 1) + (jnz = 3) = 5... чтото тут нето... но всё равно вывод очевиден... loop = dec cx, cmp cx,0 jnz loopmet... если не учитывать размер команд (3) и предвыборку, то по скорости выполнения равны. возьмём дефолтный на сегодняшний день проц... с частотой 2,4 ГГц = 2400000000 Гц. (1/2400000000)*6=0,0000000025 сек. примерно за столько выполнится ваш луп... и какой здесь может быть GetTickCount() ?? ?? про 0... процу абсолютно всё равно что сравнивать... cmp - это не что иное как вычитание... а вычитание происходит по времени одинаково независимо от значения сравниваемой переменной или константы
|
|
« Последнее редактирование: 13-12-2005 06:26 от acc15 »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #12 : 13-12-2005 07:05 » |
|
acc15 , GetTickCount() я предложил для оценки времени большого количества вычислений а не одной команды проца ЗЫ. Какая разница, предугадывание, луп не луп, если один код выполнится за 10 с, а другой за 1 с (это к примеру) ?
|
|
|
Записан
|
|
|
|
acc15
Гость
|
|
« Ответ #13 : 13-12-2005 08:09 » |
|
прикасаясь к теме... там сказано что сравнение с нулём быстрее чем с другим числом... вот я и написал...
если одинаковый по действию код выполнится позже другого то значит что в том коде который выполнится медленнее есть лишние действия... а какие могут быть лишние действия в простом сравнении? ? ? ?
|
|
« Последнее редактирование: 13-12-2005 08:20 от acc15 »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #14 : 13-12-2005 08:43 » |
|
acc15 , да эт всё понятно, лишнего нет, дело в другом: как прогу на СИ перелопатит компилятор
|
|
|
Записан
|
|
|
|
Mayk
Гость
|
|
« Ответ #15 : 30-12-2005 05:29 » |
|
Ну во-первых это не та эффективность которую стоит добиваться. Если что-то работает медленно, то шанс добится выигрыша в скорости используя этот способ равен нулю. прикасаясь к теме... там сказано что сравнение с нулём быстрее чем с другим числом... вот я и написал... если одинаковый по действию код выполнится позже другого то значит что в том коде который выполнится медленнее есть лишние действия... а какие могут быть лишние действия в простом сравнении? ? ? ?
Само сравнение. У процессора есть флаг "Ноль ли число" но у него нет флага "равно ли число 1924" 3. Делать проверку сразу после декременирования DEC AX (или ячейка памяти) JNZ ...... Но этот вариант очень маловероятен по логике построения комманд компилятором.
Вот здесь сравнения нет. Кстати, некоторые компиляторы используют sub blabla,1. в общем имхо низкоуровневую оптимизацию надо оставить компилятору.
|
|
|
Записан
|
|
|
|
acc15
Гость
|
|
« Ответ #16 : 30-12-2005 13:28 » |
|
Само сравнение. У процессора есть флаг "Ноль ли число" но у него нет флага "равно ли число 1924" вот именно что он есть, и устанавливается он только по исполнению некоторых команд процессора, к примеру тот же cmp устанавливает эти флаги, поэтому сравнение необходимо для установки флагов, по которым будет выполнен условный джамп. Сравнение с 0, а не с 1924, не путай, если ты про это про 0... процу абсолютно всё равно что сравнивать... cmp - это не что иное как вычитание... а вычитание происходит по времени одинаково независимо от значения сравниваемой переменной или константы то если сравнивать 1924 или 0 это всё равно. просто поменяются флаги.
|
|
|
Записан
|
|
|
|
Mayk
Гость
|
|
« Ответ #17 : 31-12-2005 10:21 » |
|
вот именно что он есть, и устанавливается он только по исполнению некоторых команд процессора, к примеру тот же cmp устанавливает эти флаги, поэтому сравнение необходимо для установки флагов, по которым будет выполнен условный джамп.
Если сделать sub <Ваш-Любимый-Регистр>, 1 то флаги и так поменияются. Не надо будет сравнивать. Не надо делать cmp. Вычитание уже сделано. Флаги уже установлены. Сравнение с нулем в общем случае конечно не бессмысленно, но после sub'а и dec'а смысла в нём всё же нет. Никакого. ZF уже и так установлен в 1, если результат 0.Команду cmp ,0 можно выкинуть.
|
|
« Последнее редактирование: 20-12-2007 19:17 от Алексей1153++ »
|
Записан
|
|
|
|
acc15
Гость
|
|
« Ответ #18 : 01-01-2006 15:07 » |
|
впринципе ты прав, но если тебе не нужно вычитание, а нужно именно сравнение, то как тогда быть? только cmp...
хотя я нашел ошибку... loop = dec cx, cmp cx,0 jnz loopmet... без cmp.. т.к. не нужен..
|
|
« Последнее редактирование: 01-01-2006 15:09 от acc15 »
|
Записан
|
|
|
|
|