
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.218] |
![]() |
|
Страницы: (31) « Первая ... 16 17 [18] 19 20 ... 30 31 ( Перейти к последнему сообщению ) |
Сообщ.
#256
,
|
|
|
Цитата AndNot @ ![]() Я ж говорю если нужна именно скорость тогда твой выбор 100% не Python. Однако если тебе важны: классы, высокоуровневые структуры данных и подобное тогда Python это как раз то что доктор прописал. Благодаря всему этому даже математика на Python это наслаждение. Я это понял после того как пробился с комплексными в Delphi это было что то. Я молчу о вводе/выводе ![]() ![]() Цитата AndNot @ Не надо так категорично, подозреваю что по скорости он им здорово проиграет, по крайней мере С. Подозреваешь верно! ![]() ![]() ![]() Поэтому IMHO идеальной была бы связка в виде: Человек 1) Язык(Языки) высокого уровня 2) Парсер языка(языков) высокого уровня преобразующий код в asm 3) Компилятор ASMa Машина Достоинства: решает языковую проблему! Языком высокого уровня может быть что угодно. А при грамотно написанном парсере можно будет даже использовать все достоинства всех языков. Нечто вроде html к примеру вставил Цитата и понесся <pascal>begin end </pascal> ![]() Цитата и лови свой кайф. Тем не менее остается место и для охочих до скорости (asm) и простор для совершенствования как самого языка высокого уровня так и остальных звеньев цепочки...<asm></asm> А вот кстати та темка где я скорость работы Python и Delphi сравнивал Python vs Delphi |
Сообщ.
#257
,
|
|
|
Цитата best_lamer @ Я ж говорю если нужна именно скорость тогда твой выбор 100% не Python. Однако если тебе важны: классы, высокоуровневые структуры данных и подобное тогда Python это как раз то что доктор прописал. Благодаря всему этому даже математика на Python это наслаждение. Я это понял после того как пробился с комплексными в Delphi это было что то. Я молчу о вводе/выводе ![]() ![]() ИМХО, можно вкратце сказать так: можно выделить два класса ситуаций, когда нужна высокая производительность: 1) Реал-тайм 2) Большие объемы данных; Идеальный язык должен быть доступен в этих двух областях (а так же в областях, не критичных по производительности кода, но критичных по производительности программиста); java и .net, например, никак не подходят к реал-тайму. |
Сообщ.
#258
,
|
|
|
Цитата best_lamer @ Все преобразования типов интерпретатор Python берет на себя. Т.е. если нет особого желания явно работать с преобразованиями типов к примеру как в Delphi то все сам сделает Python за сценой... Соответственно ошибки отсеиваются нааамного интенсивнее но при этом тратится время. Кто бы спорил. Цитата best_lamer @ Поэтому IMHO идеальной была бы связка в виде: Человек 1) Язык(Языки) высокого уровня 2) Парсер языка(языков) высокого уровня преобразующий код в asm 3) Компилятор ASMa Машина Да я доказывая это уже всю клаву разбил. Просто предложил Форт как готовую основу в качестве посредника/парсера. |
Сообщ.
#259
,
|
|
|
Цитата AndNot @ Да я доказывая это уже всю клаву разбил. Просто предложил Форт как готовую основу в качестве посредника/парсера. Прошу прощения я тему с самого начала не читал ![]() |
Сообщ.
#260
,
|
|
|
Цитата AndNot @ Причем здесь приоритет? Дело то в том, что после умножения DWORD на DWORD результат получается QWORD, который может просто не влезть в int. И деление после этого логично производить именно от промежуточного результата, а я наблюдал другую картину ![]() Ах, вот ты про что... Ну, не влез, и чего? (кстати, беря в руки твоё же оружие: в том же x86-ассеблере можно написать imul eax,ebx - eax*ebx помещается в eax - тоже ведь возможно усечение результата). Пусть написали int x = a * b / c. Помещать a*b в QWORD? А если c == 1, то кирдык, и у нас опять усечение при помещении результата в x? Или int x = a * b * c. Тут чего делать? От усечения не избавиться. Предложенная тобой схема только оттянет конец (избавив от первого возможного усечения). Цитата Это все равно, что мол не нравится винда, ставь другую систему. Только вот аналогичных что-то не вижу ![]() При чем тут винда? Конкуренция есть в довольно многих областях софтонаписания. Цитата Это потому что ты ими не пользуешся ![]() Ты что, для микроконтроллеров пишешь? Нахрен такое сокращение на фоне геммора с поддержкой такого кода. Да и обычно в программах длина кода не сильно заметна на фоне длины кода подгружаемых библиотек и длины данных, размещаемых этой программой в памяти. Цитата Ну почему именно константа? Меня больше интересует как он адрес будет вычислять, и соответственно после этого инвертировать. ![]() ![]() ;bs.flip(i); mov edx,ecx // в ecx находится i shr edx,5 lea eax,bs (433B08h)[edx*4] and ecx,1Fh mov edx,1 shl edx,cl xor dword ptr [eax],edx |
Сообщ.
#261
,
|
|
|
Сообщ.
#262
,
|
|
|
Цитата Hryak @ Ну, не влез, и чего? Ну у меня бывали трудновылавливаемые ошибки из-за подобного кода. Цитата Hryak @ (кстати, беря в руки твоё же оружие: в том же x86-ассеблере можно написать imul eax,ebx - eax*ebx помещается в eax - тоже ведь возможно усечение результата) Если ты применяешь imul, то осознанно (например при вычислении адреса видеопамяти, где результат в принципе не выйдет за диапозон), и отловить переполнение несложно с помощью флагов, а когда нужна гарантия достоверности результата пишеш: ![]() ![]() mov eax,[xx] mul [yy] div [zz] и все. А вот в ЯВУ нет никаких средств проконтролировать подобные ситуации. Цитата Hryak @ Помещать a*b в QWORD? А если c == 1, то кирдык, и у нас опять усечение при помещении результата в x? Во первых не усечение а исключение 0, соответственно обработчик отловит и примет меры ![]() Цитата Hryak @ Или int x = a * b * c Это из другой области. Цитата Hryak @ Да и обычно в программах длина кода не сильно заметна на фоне длины кода подгружаемых библиотек и длины данных, размещаемых этой программой в памяти. Ага, особенно когда Дельфовские запускаешь ![]() Да и почему не воспользоваться, если возможность подвернется. Цитата Hryak @ ![]() ![]() ;bs.flip(i); mov edx,ecx // в ecx находится i shr edx,5 lea eax,bs (433B08h)[edx*4] and ecx,1Fh mov edx,1 shl edx,cl xor dword ptr [eax],edx Ужас, теперь всю ночь спать не буду ![]() Можно ведь и проще: ![]() ![]() mov eax,[i] ; i - номер бита btc [BitField],eax Вроде получше, можно получить доступ к любому из 2^31 биту ![]() И насчет выразительности Си и Форта ![]() Цитата Другая "особенность" char str[50]="qwertyuio"; int a=3;str[++a]=str[++a]=' '; cout<<str<<"\n"; str[a++]=str[a++]=' '; cout<<str<<"\n"; Результат: qwe tyuio qwert uio По логике вещей должны быть добавлены два пробела. Но у C своя логика, так что это не ошибка компилятора, а особенность языка. int i=0,ar[2]={10,11}; i=ar[i++];// А кто сразу скажет чему равно значение i Цитата Примеры: Паскаль: if Screen.Forms[I] is FormClass then begin C++: if (dynamic_cast<FormClass*>(Screen - >Forms[I])){ A=(!CL&&!RC)?0 : (!LC?RC:LC)//"Очень понятное выражение" *++* agrv //"Еще одно очень понятное выражение, при том синтаксически верное" "Интуитивно понятный" синтаксис прекрасно подчеркивает следующий пример: int i=5; int * const p3=&i;//Указатель константу const int * p3=&i;//Указатель на константу i=5;//Правильно *p3=5; Неверно! указатель на константу измененную в предыдущей строке. char (*(*x2 ())[]) () //Срочно позовите криптоаналитика !!! Или работа с перечислениями: enum modes { LASTMODE , BW40 , C40, BW80, C80, MONO } ; .. modes e1=C80,e2; e1=e2*3; //Очень осмысленный оператор на "ЯПВУ". //Ведь для "ЯПВУ" нет разницы, что int, что enum, что bool А что может значить, по Вашему мнению, команда a=24[ar]; ? При условии, что int ar[50]; int a; она полностью эквивалентна a:=ar[24]; Как совершенно справедливо замечают поклонники C/C++ эти языки позволяют писать чрезвычайно краткие и выразительные программы. На счет краткости - безусловно. А вот к какой выразительности может привести краткость, я сейчас покажу: #include <stdio.h> #define Q r=R[*p++ - '0'];while( #define B ;break;case char*s="Qjou!s\\311^ - g\\311^ - n\\311^ - c\\::^ - q - ma%mO1JBHm%BQ - aP1J[O1HB%[Q<nbj\ o)*|gps)<<*txjudi)m*|aQdbtf!::::;sfuvso<aQefgbvmu;aQ<m,,a%CQ<csfbla%bQ<aN2!Q\ \ndbtf!aP2Q;m>aP2Q<a%!D12J!JGJHJOJQJFJSJJJMHS%HD12D12N3!N4\nJUJT%UQm>aP4HC%T\ Qs\\q,,^>m,2<m>aP4HC%SD12N1\nJNQm>s\\..q^aHC%NHb%GN1!D32P3%RN1UP1D12JPQUaP1H\ R%PN4\nQ<g\\(aP3Q(^>aP2Q,2<n\\(aP3Q(^>aP4Hb%OD12D12N2!N3\nJVP3Q,,<jg)aP3Q=>n\ \\(aP3Q(^*m>g\\(aP3Q(^<fmtf!m,,aHC%QN1!N1\nJ#Qqsjoug)#&e]o# - aP1Q*aHb%#Qqvut)\ aP1Q*aHb%FN1\nQm>::::aHC%VP3Q>bupj)hfut)c**aHb%JD12JON1!Qjg)a%LN1UP1D12JIQUa\ P1HL%IQ*m>aN2!N2\nP2Q<fmtf!m,,aHC%MN1!N2>P2Q>aN2\nP2Hbdd!b/d";int k;char R[4][99] ;main(c,v)char**v;{char*p,*r,*q;for(q=s;*q;q++)*q>' '&&(*q) - - ;{FILE*i=fopen(v [1],"r"),*o=fopen(q - 3,"w");for(p=s;;p++)switch(*p++){B'M':Q(k=fgetc(i))!=EOF &&k!=*p)*r++=k;if(k==EOF){fputs("}}\n",o);fclose(o);return system(q - 6);}*r=0 B'P':while(*p!='`')fputc(*p++,o)B'O':Q*r)fputc(*r++,o);p - - B'C':k=0;Q k<*p - '0' )(*r++=fgetc(i),k++);*r=0 B'I':k= *p;if(**R==k)goto G B'G':k= *p;G:p=s;while( *p!='$'||p[1]!= k)p++;p++B'N':R[*p - '0'][0]++;}}} Эта программа всего в 17 строчках текстового режима VGA(25X80) представляет собой полнофункциональный интерпретатор языка Basic, который поддерживает: Переменные(имена от A до Z), которые инициализируются нулевыми значениями при запуске. Цикл FOR var = exp TO exp ..NEXT var Подпрограммы GOSUB exp и RETURN Естественно, оператор GOTO(какой же Basic без GOTO) Условия IF exp THEN exp Комментарий REM any text Оператор конец программы END Присвоение var = exp Ввод INPUT variable И вывод PRINT string PRINT exp Есть ли читатели, которые по - прежнему считают, что краткость - это всегда очень хорошо. А читабельность конструкций языка факт второстепенный ? Цитата Кстати, многие средства языка, которые, по мнению его поклонников, появились в C++, были заимствованы из других языков. К примеру, аналог шаблонов - пакеты - были в АДЕ до создания C++. Обработка исключительных ситуаций присутствует в АДЕ и даже в PL/1.Перезагрузка операций также присутствовала в АДЕ. Copyright© Костин Г.В., 2003 Кстати что то за Аду еще никто не вставил две копейки. |
Сообщ.
#263
,
|
|
|
Цитата AndNot @ а когда нужна гарантия достоверности результата пишеш: ![]() ![]() mov eax,[xx] mul [yy] div [zz] и все. Еще раз. Хорошо, частный случай неплохо обработал. Что будешь делать с xx*yy*zz/aa ? Цитата Цитата Hryak @ Помещать a*b в QWORD? А если c == 1, то кирдык, и у нас опять усечение при помещении результата в x? Во первых не усечение а исключение 0, соответственно обработчик отловит и примет меры ![]() Не понял - откуда исключение? ![]() Цитата Цитата Hryak @ Да и обычно в программах длина кода не сильно заметна на фоне длины кода подгружаемых библиотек и длины данных, размещаемых этой программой в памяти. Ага, особенно когда Дельфовские запускаешь ![]() Не про делфи разговор ![]() Цитата Да и почему не воспользоваться, если возможность подвернется. А что, по-твоему, читаемость программы не уменьшится при этом? Цитата Цитата Hryak @ ![]() ![]() ;bs.flip(i); mov edx,ecx // в ecx находится i shr edx,5 lea eax,bs (433B08h)[edx*4] and ecx,1Fh mov edx,1 shl edx,cl xor dword ptr [eax],edx Ужас, теперь всю ночь спать не буду ![]() Можно ведь и проще: ![]() ![]() mov eax,[i] ; i - номер бита btc [BitField],eax Кому проще-то? Программисту? Так ведь не он это пишет, а компилятор. Цитата Вроде получше Кому лучше? Компилятору? А ты уверен, что твой код быстрее будет выполняться, чем показанный мной? Зуб дашь? Цитата Забрел на сайтик, и прикололся, автор явно лучше меня знает Си: Цитата Другая "особенность" ... По логике вещей должны быть добавлены два пробела. Но у C своя логика, так что это не ошибка компилятора, а особенность языка. .... i=ar[i++];// А кто сразу скажет чему равно значение i .... Все пляски вокруг всё того же (++i)++ - достаточно один раз запомнить, чтобы не наступать на эти грабли. Цитата Паскаль: if Screen.Forms[I ] is FormClass then begin C++: if (dynamic_cast<FormClass*>(Screen - >Forms[I ])){ Ой, чуть длиннее, сахара мало положили. Зато все преобразования (static_cast, dynamic_cast, reinterpret_cast, const_cast) имеют одинаковый вид. Цитата "Интуитивно понятный" синтаксис прекрасно подчеркивает следующий пример: int i=5; int * const p3=&i;//Указатель константу const int * p3=&i;//Указатель на константу Всё, что данный пример подчеркивает - дак это то, что "авторитет", писавший эту статью, не знает C++ даже на уровне одного семестра изучения в институте. int * const p3 - это не указатель константу, а константный указатель. Правило построения определений в C/C++ очень простое - просто его надо знать. Цитата char (*(*x2 ())[]) () //Срочно позовите криптоаналитика !!! 0. Крипноаналитик не нужен - выражение довольно легко читается программистом на C/C++. 1. Не зови крипноаналитика и не используй указатели на функции (или пиши на языке, который не позволяет их использовать). 2. Если не хочешь никого запутывать, вместо ![]() ![]() char (*(*x2 ())[]) (); ![]() ![]() typedef char func(); typedef func* arr[]; arr* x2(); Цитата Или работа с перечислениями: enum modes { LASTMODE , BW40 , C40, BW80, C80, MONO } ; .. modes e1=C80,e2; e1=e2*3; Не скомпилируется на C++. Цитата А что может значить, по Вашему мнению, команда a=24[ar]; ? Никто не заставляет так писать. Цитата A=(!CL&&!RC)?0 : (!LC?RC:LC)//"Очень понятное выражение" *++* agrv //"Еще одно очень понятное выражение, при том синтаксически верное" .... А вот к какой выразительности может привести краткость, я сейчас покажу: Привело, и что? На любом языке можно писать нечитаемые программы. Что из этого следует? Цитата Кстати, многие средства языка, которые, по мнению его поклонников, появились в C++, были заимствованы из других языков. К примеру, аналог шаблонов - пакеты - были в АДЕ до создания C++. Обработка исключительных ситуаций присутствует в АДЕ и даже в PL/1.Перезагрузка операций также присутствовала в АДЕ. Вроде Бьярн никогда и не скрывал, откуда он чего позаимствовал. Чего в этом плохого-то? "Перезагрука" ![]() ![]() ![]() Цитата Кстати что то за Аду еще никто не вставил две копейки. А чего за неё вставлять? Приложения, насколько я знаю, получаются сверхнадежными, но и писать их сверхсложно. |
Сообщ.
#264
,
|
|
|
Цитата Hryak @ Приложения, насколько я знаю, получаются сверхнадежными, но и писать их сверхсложно this language for american soldiers only ![]() ![]() ![]() Добавлено Цитата AndNot @ Цитата (impik777 @ Вчера, 15:43) а для чего по твоему существует инкапсуляция, контроль типов и т.д. блин, ну причем здесь ошибки логики программы? ошибки логики становятся ошибками синтаксиса, а их отслеживает компилятор блин, ты почитай про современные методы проектирования и программирования ![]() Добавлено Цитата AndNot @ Цитата (impik777 @ Вчера, 15:43) в примитиве ini файл более глубоко - использование интерпретирующихся скриптов Это отстой а не программа, если она может заглючить от неверно прописанного INI. да, и почему большинство серьезных игр и EIS'ок имеют скрипты и ini файлы ???? ![]() ![]() Добавлено Цитата AndNot @ Забрел на сайтик ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() да, такой хохмы я давно не видел, новички в университетах, и то так не пишут, а уж они перлы выдают те еще, Добавлено Цитата AndNot @ #include <stdio.h> #define Q r=R[*p++ - '0'];while( #define B ;break;case char*s="Qjou!s\\311^ - g\\311^ - n\\311^ - c\\::^ - q - ma%mO1JBHm%BQ - aP1J[O1HB%[Q<nbj\ o)*|gps)<<*txjudi)m*|aQdbtf!::::;sfuvso<aQefgbvmu;aQ<m,,a%CQ<csfbla%bQ<aN2!Q\ \ndbtf!aP2Q;m>aP2Q<a%!D12J!JGJHJOJQJFJSJJJMHS%HD12D12N3!N4\nJUJT%UQm>aP4HC%T\ Qs\\q,,^>m,2<m>aP4HC%SD12N1\nJNQm>s\\..q^aHC%NHb%GN1!D32P3%RN1UP1D12JPQUaP1H\ R%PN4\nQ<g\\(aP3Q(^>aP2Q,2<n\\(aP3Q(^>aP4Hb%OD12D12N2!N3\nJVP3Q,,<jg)aP3Q=>n\ \\(aP3Q(^*m>g\\(aP3Q(^<fmtf!m,,aHC%QN1!N1\nJ#Qqsjoug)#&e]o# - aP1Q*aHb%#Qqvut)\ aP1Q*aHb%FN1\nQm>::::aHC%VP3Q>bupj)hfut)c**aHb%JD12JON1!Qjg)a%LN1UP1D12JIQUa\ P1HL%IQ*m>aN2!N2\nP2Q<fmtf!m,,aHC%MN1!N2>P2Q>aN2\nP2Hbdd!b/d";int k;char R[4][99] ;main(c,v)char**v;{char*p,*r,*q;for(q=s;*q;q++)*q>' '&&(*q) - - ;{FILE*i=fopen(v [1],"r"),*o=fopen(q - 3,"w");for(p=s;;p++)switch(*p++){B'M':Q(k=fgetc(i))!=EOF &&k!=*p)*r++=k;if(k==EOF){fputs("}}\n",o);fclose(o);return system(q - 6);}*r=0 B'P':while(*p!='`')fputc(*p++,o)B'O':Q*r)fputc(*r++,o);p - - B'C':k=0;Q k<*p - '0' )(*r++=fgetc(i),k++);*r=0 B'I':k= *p;if(**R==k)goto G B'G':k= *p;G:p=s;while( *p!='$'||p[1]!= k)p++;p++B'N':R[*p - '0'][0]++;}}} ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() валяюсь под столом |
Сообщ.
#265
,
|
|
|
Цитата Hryak @ Еще раз. Хорошо, частный случай неплохо обработал. Что будешь делать с xx*yy*zz/aa ? Можно хотя бы и так: ![]() ![]() mov eax,[xx] imul [yy] jc __long_mul ; результат не умещается в edx:eax, уходим на длинную арифметику imul [zz] jc __long_mul2 idiv [aa] Гарантированно получишь корректный результат ![]() Цитата Hryak @ Цитата Цитата Цитата (Hryak @ 15.10.06, 20:54) Помещать a*b в QWORD? А если c == 1, то кирдык, и у нас опять усечение при помещении результата в x? Во первых не усечение а исключение 0, соответственно обработчик отловит и примет меры ![]() Не понял - откуда исключение? ![]() Если, при выполнении деления, результат(частное) не умещается в регистр, то процессор генерит "исключение 0 - переполнение при делении, или деление на ноль"(тип Fault), сохраняет в стеке адрес бад-команды и передает управление обработчику исключения. Понял в чем кайф? И если программа не установила свой обработчик, то винда просто завершит программу. Цитата Hryak @ Цитата Да и почему не воспользоваться, если возможность подвернется. А что, по-твоему, читаемость программы не уменьшится при этом? Частенько наоборот, читаемость улучшается, за счет сокращения размера сорсов (актуально для асма). Цитата Hryak @ Кому проще-то? Программисту? Так ведь не он это пишет, а компилятор. А разговор начинался про средства оптимизации компиляторов ЯВУ, а они, как показывает практика, частенько тупят. Даже интеловский Си бывает выдает ляпы. С другой стороны сам вопрос об оптимизации спорный. Уже давно процессоры сами меняют очередность команд, используют переименование регистров и прочие трюки. Так что о распаралеливании команд в сорсах можно в принципе и не задумываться, особо заметного проигрыша не будет. А вообще говоря об оптимизации что имеется в виду? Архитектур много, и если на одном процессоре получищь большой прирост по скорости, то на другом, скорее всего, получишь охрененные тормоза. Где золотая середина? Цитата Hryak @ Цитата Вроде получше Кому лучше? Компилятору? А ты уверен, что твой код быстрее будет выполняться, чем показанный мной? Зуб дашь? Даже больше чем уверен, хотя бы потому, что сдвиги с операндом в CL не спариваются (как и BTC), и времени жрет как и BTC. Так что код компилятора не просто плохой, он отвратительный, наглядный пример как не надо делать. Цитата impik777 @ ошибки логики становятся ошибками синтаксиса С какого перепуга ![]() Цитата impik777 @ да, и почему большинство серьезных игр и EIS'ок имеют скрипты и ini файлы ???? Я не про это. Читай внимательнее. Ну а теперь всем сразу по поводу приведенных перлов Си. Главное не то как на нем большинство пишет, главное что он позволяет такую чушь писать. Цитата "С точки зрения теоретического программирования язык си - это Фортран 80 - ых. (Против такого уничижительного определения не возражал и автор языка Си - Д. Ритчи). Этот язык, сочетающий в себе многие преимущества языка высокого уровня и ассемблера, дал программистам, по образному выражению некоторых, педаль газа, но заблокировал педаль тормоза. На Си компьютер может "мчаться" быстро, но рискованно. То есть Си, насаждая ссылочно - ассемблерное программирование, как бы имеет вектор в сторону, противоположную той, которая определяется теорией и методологией языков программирования. Поэтому и Си++ - это довольно странное сочетание некоторых черт ООП (здесь и далее - объектно - ориентированное программирование) и процедурного программирования" К.Т.Н. Соловьев А.Е. |
Сообщ.
#266
,
|
|
|
Цитата AndNot @ Цитата Hryak @ Еще раз. Хорошо, частный случай неплохо обработал. Что будешь делать с xx*yy*zz/aa ? Можно хотя бы и так: ![]() ![]() mov eax,[xx] imul [yy] jc __long_mul ; результат не умещается в edx:eax, уходим на длинную арифметику imul [zz] jc __long_mul2 idiv [aa] Гарантированно получишь корректный результат ![]() Т.е. будет ветка с нормальной арифметикой, ветка с длинной, со сверхдлинной и т.д. А результат куда денешь? Тоже будешь делать нормальный результат, длинный результат, сверхдлинный результат и т.д.? А потом этот результат будет использоваться в другом выражении - там все повторится в коде, но уже три раза (по разу на каждый вариант предыдущего шага). Колонии микробов в плане размножения отдыхают. ![]() Цитата Если, при выполнении деления, результат(частное) не умещается в регистр, то процессор генерит "исключение 0 - переполнение при делении, или деление на ноль"(тип Fault), сохраняет в стеке адрес бад-команды и передает управление обработчику исключения. Понятно, я сразу не понял о чем речь. Цитата Цитата Hryak @ А что, по-твоему, читаемость программы не уменьшится при этом? Частенько наоборот, читаемость улучшается, за счет сокращения размера сорсов (актуально для асма). Не знаю, что там актуально для асма (не спец), но для языков высокого уровня бóльшее значение имеет упорядоченность исходников и простота взаимосвязей кода. И то, и другое будет страдать от подобных фишек. И если при программировании на языке высокого уровня проявляется желание в конкретном месте поюзать такое - значит пришло время для выделения части кода в отдельную функцию. Цитата А разговор начинался про средства оптимизации компиляторов ЯВУ, а они, как показывает практика, частенько тупят. Даже интеловский Си бывает выдает ляпы. Ничего совершенного не существует. Ляпы оптимизатора - фигня, если язык позволяет писать гораздо быстрее, ненапряжнее и надежнее код, чем ассемблер, а уж существенные ляпы, резко снижающие скорость выполнения критичных участков кода так, что это становится заметно, можно и ручками переписать на том же асме. Цитата С другой стороны сам вопрос об оптимизации спорный. Уже давно процессоры сами меняют очередность команд, используют переименование регистров и прочие трюки. Так что о распаралеливании команд в сорсах можно в принципе и не задумываться, особо заметного проигрыша не будет. А вообще говоря об оптимизации что имеется в виду? Архитектур много, и если на одном процессоре получищь большой прирост по скорости, то на другом, скорее всего, получишь охрененные тормоза. Где золотая середина? Золотая середина как раз в языках высокого уровня. ![]() Цитата Цитата Hryak @ Цитата Вроде получше Кому лучше? Компилятору? А ты уверен, что твой код быстрее будет выполняться, чем показанный мной? Зуб дашь? Даже больше чем уверен, хотя бы потому, что сдвиги с операндом в CL не спариваются (как и BTC), и времени жрет как и BTC. Так что код компилятора не просто плохой, он отвратительный, наглядный пример как не надо делать. inc eax дольше чем add eax,1 loopnz работает дольше чем sub ecx,1 jnz; на большинстве современных процов. btc - сложная инструкция по определению. Поэтому я решил накидать маленький тест. Попрошу тебя прокомментировать результаты: Исходный код на C++: ![]() ![]() #include <iostream> #include <bitset> #include <Windows.h> const int nbits = 300000; std::bitset<nbits> bs; void DoFlip(int cnt) { for (int i = 0; i < cnt; ++i) { for (int j = 0; j < nbits; ++j) bs.flip(j); } } void DoBtc(int cnt) { for (int i = 0; i < cnt; ++i) { for (int j = 0; j < nbits; ++j) { __asm { mov eax,j btc bs, eax // исключительно в целях теста } } } } #pragma inline_depth(0) int main() { int i; std::cin >> i; DWORD st; st = GetTickCount(); DoFlip(i); std::cout << "DoFlip time: " << GetTickCount()-st << " ms\n"; st = GetTickCount(); DoBtc(i); std::cout << "DoBtc time: " << GetTickCount()-st << " ms\n"; } Последствия работы компилятора (VC++8.0): ![]() ![]() DoBtc: 0041AAF0 push ecx 0041AAF1 test eax,eax 0041AAF3 jle DoBtc+2Dh (41AB1Dh) 0041AAF5 mov edx,eax 0041AAF7 xor ecx,ecx 0041AAF9 mov dword ptr [esp],ecx 0041AAFC lea esp,[esp] 0041AB00 mov eax,dword ptr [esp] 0041AB03 btc dword ptr [bs (4237F8h)],eax 0041AB0A add ecx,1 0041AB0D cmp ecx,493E0h 0041AB13 mov dword ptr [esp],ecx 0041AB16 jl DoBtc+10h (41AB00h) 0041AB18 sub edx,1 0041AB1B jne DoBtc+7 (41AAF7h) 0041AB1D pop ecx 0041AB1E ret ...... DoFlip: 0041AB20 push ecx 0041AB21 push ebx 0041AB22 push esi 0041AB23 xor esi,esi 0041AB25 test edi,edi 0041AB27 jle DoFlip+44h (41AB64h) 0041AB29 lea esp,[esp] 0041AB30 xor eax,eax 0041AB32 cmp eax,493E0h 0041AB37 jae DoFlip+48h (41AB68h) 0041AB39 mov ecx,eax 0041AB3B shr ecx,5 0041AB3E lea edx,bs (4237F8h)[ecx*4] 0041AB45 mov ecx,eax 0041AB47 and ecx,1Fh 0041AB4A mov ebx,1 0041AB4F shl ebx,cl 0041AB51 add eax,1 0041AB54 xor dword ptr [edx],ebx 0041AB56 cmp eax,493E0h 0041AB5B jl DoFlip+17h (41AB37h) 0041AB5D add esi,1 0041AB60 cmp esi,edi 0041AB62 jl DoFlip+10h (41AB30h) 0041AB64 pop esi 0041AB65 pop ebx 0041AB66 pop ecx 0041AB67 ret 0041AB68 jmp std::bitset<300000>::_Xran (402660h) ........ int main() { 0041AB70 push ebp 0041AB71 mov ebp,esp 0041AB73 and esp,0FFFFFFF8h 0041AB76 push ecx 0041AB77 push ebx 0041AB78 push esi 0041AB79 push edi int i; std::cin >> i; 0041AB7A lea eax,[esp+0Ch] 0041AB7E push eax 0041AB7F call std::basic_istream<char,std::char_traits<char> >::operator>> (401F60h) DWORD st; st = GetTickCount(); 0041AB84 mov esi,dword ptr [__imp__GetTickCount@0 (41C000h)] 0041AB8A call esi DoFlip(i); 0041AB8C mov edi,dword ptr [esp+0Ch] 0041AB90 mov ebx,eax 0041AB92 call DoFlip (41AB20h) std::cout << "DoFlip time: " << GetTickCount()-st << " ms\n"; 0041AB97 push 41E728h 0041AB9C push ecx 0041AB9D call esi 0041AB9F sub eax,ebx 0041ABA1 push eax 0041ABA2 push ecx 0041ABA3 push 41E730h 0041ABA8 push offset std::cout (4235F8h) 0041ABAD call std::operator<<<std::char_traits<char> > (4059C0h) 0041ABB2 add esp,0Ch 0041ABB5 push eax 0041ABB6 call std::basic_ostream<char,std::char_traits<char> >::operator<< (401DA0h) 0041ABBB add esp,4 0041ABBE push eax 0041ABBF call std::operator<<<std::char_traits<char> > (4059C0h) 0041ABC4 add esp,8 st = GetTickCount(); 0041ABC7 call esi 0041ABC9 mov ebx,eax DoBtc(i); 0041ABCB mov eax,edi 0041ABCD call DoBtc (41AAF0h) std::cout << "DoBtc time: " << GetTickCount()-st << " ms\n"; 0041ABD2 push 41E740h 0041ABD7 push ecx 0041ABD8 call esi 0041ABDA sub eax,ebx 0041ABDC push eax 0041ABDD push ecx 0041ABDE push 41E748h 0041ABE3 push offset std::cout (4235F8h) 0041ABE8 call std::operator<<<std::char_traits<char> > (4059C0h) 0041ABED add esp,0Ch 0041ABF0 push eax 0041ABF1 call std::basic_ostream<char,std::char_traits<char> >::operator<< (401DA0h) 0041ABF6 add esp,4 0041ABF9 push eax 0041ABFA call std::operator<<<std::char_traits<char> > (4059C0h) 0041ABFF add esp,8 } 0041AC02 pop edi 0041AC03 pop esi 0041AC04 xor eax,eax 0041AC06 pop ebx 0041AC07 mov esp,ebp 0041AC09 pop ebp 0041AC0A ret А вот и результаты (на тысяче итераций инвертирования всех бит): Pentium4 2400 Northwood: ![]() ![]() 1000 DoFlip time: 1094 ms DoBtc time: 2234 ms Athlon XP 2500+ Barton: ![]() ![]() D:\MyProjects\_TESTS\ConsoleTest3\Release>ConsoleTest3_seq.exe 1000 DoFlip time: 875 ms DoBtc time: 2250 ms Цитата Ну а теперь всем сразу по поводу приведенных перлов Си. Главное не то как на нем большинство пишет, главное что он позволяет такую чушь писать. Слушай, хватит уже, а? Уже в который раз повторяешь одно и тоже. Ты лучше скажи, почему это позволение так плохо. Знаешь, какие убийства самые распространённые? Отвечу сам - бытовые. А знаешь, какое самое распространённое оружие, используемое при этом? Отвечу сам - обыкновенный кухонный нож. Ты, зная это, призываешь запретить изготовление и свободную продажу этих убийственных вещей, да? И сам их в руки не берешь? По поводу "позволения писать чушь". Мне кажется, что на Форте с его-то гибкостью можно не менее неперевариваемую чушь изобразить. И чего из этого следует? Цитата К.Т.Н. Соловьев А.Е. Потому и кандидат только. ![]() |
Сообщ.
#267
,
|
|
|
Цитата Т.е. будет ветка с нормальной арифметикой, ветка с длинной, со сверхдлинной и т.д. А результат куда денешь? Достаточно одной операции длинного умножения и деления. Цитата Не знаю, что там актуально для асма (не спец), но для языков высокого уровня бo'льшее значение имеет упорядоченность исходников и простота взаимосвязей кода. И то, и другое будет страдать от подобных фишек. Беда асма - большой объем сорсов. И отчасти поэтому стараешся при любой возможности его уменьшить, вот и получается зачастую лучшая читабельность. Цитата Ничего совершенного не существует. Ляпы оптимизатора - фигня, если язык позволяет писать гораздо быстрее, ненапряжнее и надежнее код, чем ассемблер, а уж существенные ляпы, резко снижающие скорость выполнения критичных участков кода так, что это становится заметно, можно и ручками переписать на том же асме. Зачем же сразу на асм. В ЯВУ нет средств управлять выравниванием кода и данных, поэтому бывают случаи когда убираешь с функции инлайн, и программа начинает ощутимо быстрее работать. Цитата При компиляции исходника я могу выставить, под какой процессор мне проводить оптимизацию. Ага, ты поставил оптимизацию под Pentium Pro (был такой), а пользователь имеет Первопень. Я на себе ощутил, какие его ждут тормоза. Если бы такие тормоза стояли на машинах, то аварий было бы значительно меньше. Цитата Можно сделать несколько версий программы путем простого перекомпилирования с нужными ключами. ![]() Цитата Колонии микробов в плане размножения отдыхают. ![]() Цитата Поэтому я решил накидать маленький тест. Попрошу тебя прокомментировать результаты: Цитата ![]() ![]() 0041AAF9 mov dword ptr [esp],ecx 0041AAFC lea esp,[esp] 0041AB00 mov eax,dword ptr [esp] Без слов. Цитата Комментарии в студию! ![]() ![]() Впрочем сам тест написан не совсем верно. Во первых тестировать надо в ДОСе (догадываешься почему?). Во вторых я уже сталкивался с ситуацией, когда на результаты очень сильно сказывалось расположение тестируемых подпрограмм (относительно друг друга), последствия кеша. В третьих, GetTickCount() не самый лучший выбор (очень большая погрешность). И в четвертых, вот тебе достоверный тест: ![]() ![]() ; tasm /la /m2 /zi speed.asm ; wlink system dos4g file speed name 0000 IDEAL P386 MODEL FLAT ,PASCAL SMART LOCALS __ ; pазpешаем локальные идентефикатоpы NOJUMPS ; запpещаем TASM'у подставлять NOP'ы ITER = 320000 ; для 320000 полей OVERHEAD = 17 ; 15 для PPlain, 17 для PMMX MACRO RDTSC ; определяем инструкцию RDTSC DB 0FH,31H ENDM DATASEG msgResult db 'Result: ','$' msgCRLF db ' ticks',13,10,'$' UDATASEG Counter dd ? ; счетчик цикла Tics dd ? ; временная переменная для значения счетчика ResultList dd ITER DUP (?) ; список тестовых результатов ResultTics dd ? ; результат RandSeed dd ? BitField dd (ITER/32) dup (?) STACK 10000h CODESEG align 4 ; получение случайного целого числа PROC _Random NEAR __Range push edx mov eax,[__Range] imul edx,[RandSeed],08088405h inc edx mov [RandSeed],edx mul edx mov eax,edx pop edx ret ENDP _Random PROC _Speed xor eax,eax mov [Counter],eax ; начинаем отсчет cli ; запрещаем прерывания align 4 __loop: xor eax,eax ; очищаем FIFO-буфер инструкций RDTSC ; считываем значение счетчика тактов mov [Tics],eax ; сохраняем его cld ; не спариваемая инструкция REPT 8 nop ;; 8 NOP'ов, чтобы избежать эффекта "затенения" ENDM ; собственно тестирование mov ecx,[Counter] ;--------------------------------------- ; 1-я подпрограмка C++ mov edx,ecx shr edx,5 lea eax,[BitField+edx*4] and ecx,1Fh mov edx,1 shl edx,cl xor [eax],edx ; 2-я подпрограмка ASM ; btc [BitField],ecx ;--------------------------------------- ; заканчиваем отсчет clc ; инструкция против спаривания и затенения RDTSC ; снова читаем счетчик sub eax,[Tics] ; вычисляем разность sub eax,OVERHEAD ; вычитаем такты, которые использовали ; подсобные инструкции (против спаривания и ; затенения) ; сохраняем результат в таблице mov edx,[Counter] mov [ResultList+edx*4],eax inc edx mov [Counter],edx cmp edx,ITER jb __loop ; повторяем заданное количество раз sti ; разрешаем прерывания ; подсчитываем среднее значение lea esi,[ResultList] mov ecx,ITER push ecx xor ebx,ebx xor edx,edx __add: lodsd add ebx,eax adc edx,0 loop __add xchg eax,ebx pop ecx div ecx mov [ResultTics],eax ret ENDP _Speed proc _PrintEAX lea edi,[esp-4] sub esp,16 xor ebx,ebx mov ecx,10 mov [byte edi],'$' __loop: xor edx,edx div ecx dec edi add dl,'0' mov [edi],dl or eax,eax jnz __loop mov ah,9 mov edx,edi int 21h add esp,16 ret endp _PrintEAX align 4 start: jmp short _main db 'WATCOM... What me worry?' ; The "WATCOM" string is needed in ; order to run under DOS/4G and WD. _main: sti ; pазpешаем пpеpывания cld ; сбpасываем флаг напpавления push ds pop es ; заполняем BitField псевдо случайными значениями mov [RandSeed],0fa34a23h ; гарантия одинакового заполнения mov ecx,(ITER/32) lea edi,[BitField] fill: or eax,-1 call _Random,eax stosd loop fill call _Speed mov ah,9 lea edx,[msgResult] int 21h mov eax,[ResultTics] call _PrintEAX mov ah,9 lea edx,[msgCRLF] int 21h Quit: push 4C00h ; AH=4Ch - Exit To DOS pop eax int 21h ; DOS INT 21h ENDS END Start Результат (Селерон 633): C++ - 34 такта ASM - 33 такта а по размеру счет 7:24 в пользу асма ![]() Вопросы? |
Сообщ.
#268
,
|
|
|
Ага. Сразу не заметил - часть времени в DoBtc сжирала пара лишних обращений к памяти.
Привел обвязку тестируемого кода в соответствие и замерил время выполнения пустого цикла, которое затем вычел из полученных времён (понятно, что из-за всяческих причин нельзя точно посчитать чистое время выполнения сравниваемых инструкций, но всё-таки...). И время замерил через QueryPerformanceCounter. ![]() ![]() void __fastcall DoFlip(int cnt) { for (int i = 0; i < cnt; ++i) { for (int j = 0; j < nbits; ++j) { bs.flip(j); } } } __declspec(naked) void __fastcall DoBtc(int cnt) { __asm { push edi mov edi,ecx push ebx push esi xor esi,esi test edi,edi jle Exit lea esp,[esp] OuterLoop: xor eax,eax cmp eax,493E0h InnerLoop: jae OutOfRange btc bs,eax add eax,1 cmp eax,493E0h jl InnerLoop add esi,1 cmp esi,edi jl OuterLoop Exit: pop esi pop ebx pop edi ret OutOfRange: mov ecx,offset bs jmp std::bitset<300000>::_Xran } } ![]() ![]() DoFlip: 00401CE0 push ecx 00401CE1 push ebx 00401CE2 push esi 00401CE3 xor esi,esi 00401CE5 test edi,edi 00401CE7 jle 00401D24 00401CE9 lea esp,[esp+00000000h] 00401CF0 xor eax,eax 00401CF2 cmp eax,493E0h 00401CF7 jae 00401D28 00401CF9 mov ecx,eax 00401CFB shr ecx,5 00401CFE lea edx,[ecx*4+004237F8h] 00401D05 mov ecx,eax 00401D07 and ecx,1Fh 00401D0A mov ebx,1 00401D0F shl ebx,cl 00401D11 add eax,1 00401D14 xor dword ptr [edx],ebx 00401D16 cmp eax,493E0h 00401D1B jl 00401CF7 00401D1D add esi,1 00401D20 cmp esi,edi 00401D22 jl 00401CF0 00401D24 pop esi 00401D25 pop ebx 00401D26 pop ecx 00401D27 ret 00401D28 mov ecx,4237F8h 00401D2D jmp 004024E0 ....... DoBtc: 00401D40 push edi 00401D41 mov edi,ecx 00401D43 push ebx 00401D44 push esi 00401D45 xor esi,esi 00401D47 test edi,edi 00401D49 jle 00401D6F 00401D4B lea esp,[esp] 00401D4E xor eax,eax 00401D50 cmp eax,493E0h 00401D55 jae 00401D73 00401D57 btc dword ptr ds:[004237F8h],eax 00401D5E add eax,1 00401D61 cmp eax,493E0h 00401D66 jl 00401D55 00401D68 add esi,1 00401D6B cmp esi,edi 00401D6D jl 00401D4E 00401D6F pop esi 00401D70 pop ebx 00401D71 pop edi 00401D72 ret 00401D73 mov ecx,4237F8h 00401D78 jmp 004024E0 Athlon XP 2500+ Barton: ![]() ![]() 1000 DoEmptyLoop time: 531 ms DoFlip time: all = 890 ms; pure flip = 359 ms DoBtc time: all = 1062 ms; pure btc = 531 ms -Added Цитата AndNot @ Цитата Т.е. будет ветка с нормальной арифметикой, ветка с длинной, со сверхдлинной и т.д. А результат куда денешь? Достаточно одной операции длинного умножения и деления. Я не про случай a*b*c/d. Я в общем сказал. Например, a*b*c*d*e/f. Цитата Цитата При компиляции исходника я могу выставить, под какой процессор мне проводить оптимизацию. Ага, ты поставил оптимизацию под Pentium Pro (был такой), а пользователь имеет Первопень. Я на себе ощутил, какие его ждут тормоза. Тоже самое ведь будет, если ты на асме будешь писать под Pentium Pro, а у пользователя окажется Первопень. Да и проверку можно встроить в программу. Цитата ![]() ![]() Да, я уже сам заметил. Поправился. Цитата Результат (Селерон 633): C++ - 34 такта ASM - 33 такта Один такт из 34-х. ![]() Кстати, еще одна причина проседания btc в моем тесте. Заменил в DoBtc ![]() ![]() btc bs,eax add eax,1 cmp eax,493E0h ![]() ![]() add eax,1 btc bs,eax cmp eax,493E0h-1 |
Сообщ.
#269
,
|
|
|
Цитата Hryak @ и замерил время выполнения пустого цикла, Мог бы и не мучиться, у тебя два цикла, и оба по разным адресам, и с разным выравниванием! Так у тебя будут большие разбросы! Процессоры очень чувствительны к выравниванию. ![]() ![]() DoFlip: [.....] OuterLoop: 00401CF0 xor eax,eax ; выровнен на параграф 00401CF2 cmp eax,493E0h InnerLoop: 00401CF7 jae 00401D28 ; не выровнен [.....] 00401D14 xor dword ptr [edx],ebx ; выровнен на DWORD [.....] DoBtc: [.....] OuterLoop: 00401D4E xor eax,eax ; выровнен на WORD 00401D50 cmp eax,493E0h InnerLoop: 00401D55 jae 00401D73 ; не выровнен 00401D57 btc dword ptr ds:[004237F8h],eax ; не выровнен [.....] И кстати, я не вижу в этих циклах никакой оптимизации по выравниванию! На каждом InnerLoop сгорает дохрена тактов! А ведь цикл не маленький ![]() Цитата Hryak @ Я не про случай a*b*c/d. Я в общем сказал. Например, a*b*c*d*e/f И? Что мешает вставить проверку там где необходимо? Это будет лучше чем преобразовывать числа к __int64. Ведь не каждый раз происходит переполнение, и далеко не всегда будет переход на long арифметику. Мне вот встречались конструкции наподобе: ![]() ![]() for (.... { tmp = num; num += xx[i]; if (num<tmp) Carry++; } if Carry {...} А ведь все гораздо проще: ![]() ![]() @: add eax,[ebx] adc ecx,0 .... jc __ { } И выглядит попроще, и понятнее. Я уж не говорю за скорость и размер. Цитата Hryak @ оже самое ведь будет, если ты на асме будешь писать под Pentium Pro, а у пользователя окажется Первопень. Я никогда не оптимизирую под какой то конкретный проц. Мне хватает самых общих правил, одинаковых для всех процев. Это как правило уже дает неплохие результаты. А оптимизировать желательно FPU! Вот где простор! Цитата Hryak @ Да и проверку можно встроить в программу. Зачем плодить лишние ветвления и размер? Есть определенный стиль, пригодный для всех архитектур. Главное выравнивание и размер кода(кэш не резиновый). А вот с этим у ЯВУ напряженка. Цитата Hryak @ Один такт из 34-х. На более древних разница будет еще существеннее, но это и не важно. Это всего лишь частный случай, да и про размер не забывай, все таки в 3-и с лишком раза ![]() Цитата Hryak @ inc eax дольше чем add eax,1 loopnz работает дольше чем sub ecx,1 jnz; loopnz используется несколько иначе ![]() А вот насчет ADD EAX,1 и INC EAX не уверен, по моим таблицам: Цитата ADD SUB AND OR XOR r , r/i 1 uv INC DEC r 1 uv "А если нет разницы, зачем платить больше"? ©Дося ![]() |
Сообщ.
#270
,
|
|
|
INC/DEC не медленнее ADD/SUB а как раз наоборот.
Точнее начиная с Pentium2 одинаково, а на более ранних INC/DEC быстрее. И плюс ко всему при работе с аккумулятором (EAX) занимает меньше места. loop действительно медленне dec/jcc за счёт спаривания. Но опять же для процессоров Intel, на AMD всё совсем наоборот. А вообще тесты такие это всё ерунда потому что очень многое зависит от компилятора. Ты чем компилируешь? Попробуй Intel C Compiler. Хотя ни один компилятор С не обгонит в плане оптимизации нормального программиста на ASM. |