![]() |
|
|
Программирование Все о программировании .... |
Результаты опроса: Какие язык программирования вы изучали первым. | |||
С++ |
![]() ![]() ![]() ![]() |
9 | 26.47% |
BASIC |
![]() ![]() ![]() ![]() |
9 | 26.47% |
PASCAL |
![]() ![]() ![]() ![]() |
13 | 38.24% |
FORTRAN |
![]() ![]() ![]() ![]() |
1 | 2.94% |
ALGOL |
![]() ![]() ![]() ![]() |
0 | 0% |
ADA |
![]() ![]() ![]() ![]() |
0 | 0% |
КуМир |
![]() ![]() ![]() ![]() |
0 | 0% |
ASSEMBLER |
![]() ![]() ![]() ![]() |
0 | 0% |
FOCAL |
![]() ![]() ![]() ![]() |
0 | 0% |
Никогда не учил |
![]() ![]() ![]() ![]() |
2 | 5.88% |
Голосовавшие: 34. Вы ещё не голосовали в этом опросе |
![]() |
|
Опции темы | Поиск в этой теме |
![]() |
#1 | ||||
Профессиональный DJ
![]() ![]()
|
![]() ![]()
|
||||
Последний раз редактировалось SETRA; 14.12.2007 в 17:55.. |
|||||
![]() |
Cказали cпасибо: |
![]() |
#2 | |||
Профессиональный DJ
![]() ![]()
|
![]() Давно написаный алгоритм вычисления суммы прописью:
//summa.h AnsiString triada(AnsiString in, int tn) { if (in == " ") return ""; if (in == "000") return ""; AnsiString out = ""; AnsiString sotni[9] = {"сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"}; AnsiString dubl[10] = {"десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"}; AnsiString des[8] = {"двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдясят", "восемьдясят", "девяносто"}; AnsiString ed[9] = {"один", "два", "три", "четыре", "пять", "шесть","семь", "восемь", "девять"}; AnsiString edj[9] = {"одна", "две", "три", "четыре", "пять", "шесть","семь", "восемь", "девять"}; AnsiString ind[5] = {"", " тысяч", " миллион", " миллиард", " триллион"}; AnsiString post; if (in[1] != ' ') if (in[1] != '0') { out = out + sotni[StrToInt(in[1])-1]; } if (in[2] == '1') { out = out + " " + dubl[StrToInt(in[3])]; } if (in[2] != '1') if (in[2] != ' ') if (in[2] != '0') { out = out + " " + des[StrToInt(in[2])-2]; } if (in[3] != '0') if (in[2] != '1') { if (tn == 1) out = out + " " + edj[StrToInt(in[3])-1]; if (tn != 1) out = out + " " + ed[StrToInt(in[3])-1]; } if (tn>0) if (in[2] != '1') { if (tn==1) switch (in[3]) { case '1': post = ind[tn] + "а"; break; case '2': post = ind[tn] + "и"; break; case '3': post = ind[tn] + "и"; break; case '4': post = ind[tn] + "и"; break; default : post = ind[tn] + ""; break; } if ((tn==2)||(tn==3)||(tn==4)) switch (in[3]) { case '1': post = ind[tn] + ""; break; case '2': post = ind[tn] + "а"; break; case '3': post = ind[tn] + "а"; break; case '4': post = ind[tn] + "а"; break; default : post = ind[tn] + "ов"; break; } } else { switch (tn) { case 1 : post = ind[tn]; break; default : post = ind[tn] + "ов"; break; } } out = out + post; return out; } AnsiString summa(AnsiString in) { AnsiString out; AnsiString trs[5]; AnsiString tro[5]; AnsiString buf; int n,s; div_t dr; while (in.Length() < 15) { in = " " + in; } for (n=0;n<5;n++) trs[n] = in; trs[0] = trs[0].Delete(1,in.Length()-3); trs[1] = trs[1].Delete(1,in.Length()-6).Delete(4,4); trs[2] = trs[2].Delete(1,in.Length()-9).Delete(4,6); trs[3] = trs[3].Delete(1,in.Length()-12).Delete(4,9); trs[4] = trs[4].Delete(1,in.Length()-15).Delete(4,12); for (n=0;n<5;n++) { tro[n] = triada(trs[n],n); } out = " "+tro[4]+" "+tro[3]+" "+tro[2]+" "+tro[1]+" "+tro[0]+" "; out = out.Trim(); return out; } // / summa.h ![]() |
|||
![]() |
Cказали cпасибо: |
![]() |
#3 | |||
Профессиональный DJ
![]() ![]()
|
![]() Написание оптимального кода под Delphi
В данной статье рассмотрены принципы, помогающие компилятору Delphi генерировать более оптимальный с точки зрения скорости код. Если Вы не хотите вникать в подробности, в конце статьи есть «свод правил», которые рекомендуется соблюдать при написании программ. Компилятор Delphi относится к разряду оптимизирующих. Но насколько качественно проводится оптимизация? Как «помочь» компилятору создать более быстрый код? Давайте разберемся с этим на экспериментах. Оптимизация константных выражений Пример 1: const z = 15616; ... var a,b: integer; ... a := $abcd6123; b := z+a; .... С точки зрения оптимизации код можно упростить еще на этапе компиляции до b:=15616+$abcd6123; или того проще: b:=$ABCD9E23; Но написанный выше листинг преобразуется в mov eax, $abcd6123 lea ebx, [eax + $00003D00] С одной стороны компилятор не «сообразил», что значение переменной «a» можно преобразовать в константу и сложить с другой константой (которая, заметим, подставлена именно как константа) на этапе компиляции, с другой стороны был применен весьма хитрый трюк с LEA (об этом ниже). Тем не менее, код mov ebx, $ABCD9E23 в любом случае быстрее и короче. Пример 2: ... b:=random(maxint); // b – заведомо не константа ! a:=$abcd6123; if b>a then b:=a; ... Скомпилированный код будет выглядеть mov eax, $7fffffff // MaxInt call @RandInt mov ebx,eax mov eax, $abcd6123 cmp eax, ebx jnl +$02 ... А ведь значение, присвоенной переменной «а» являлось константой и наш пример можно было бы переписать как: b:=random(maxint); a:=$abcd6123; if b>$abcd6123 then b:= $abcd6123; Пример 3: ... a:=$abcd6123; b:=$abc34233; c:=b-a; ... После компиляции получаем: mov eax, $abcd6123 mov ebx, $abc34233 mov ebx, edx sub ebx, eax Т.е. компилятор преобразовал код так, как он был написан, а ведь можно было бы просто записать: mov ebx, $fff5e110 т.е. c:= $fff5e110; Оптимизация алгебраических выражений Пример 4: ... var a,b,c,d: integer; p: pointer; begin p:=nil; a:=0; ... {далее по коду эти присвоения не используются} После компиляции эти переменные будут удалены, причем с предупреждением Value assigned to ... never used Пример 5: ... a:=0; b:=a; showmessage(inttostr(b)); ... Код скомпилируется как есть! Таким образом мы обманули компилятор псевдо использованием переменных. Delphi не исправляет нашей «кривости», поэтому эта задача ложится исключительно на плечи программиста. Пример 6: ... b:=random(maxint); a:=b; func(a,b); a:=a+1; func(a,b); ... Данный код можно оптимизировать до ... b:=random(maxint); func(b,b); a:=b+1; func(a,b); ... И этого Delphi за нас не сделает. Пример 7: ... c:=a div b; c:=a*b; ... В данном примере первую строчку можно безболезненно удалить, что Delphi делать умеет. Пример 8: if ((a*b)<$3d00) and (a*b)>0)) then ... В данном случае можно избавится от одной операции умножения, присвоив значение выражения a*b временной переменной. Анализ ассемблерного листинга показывает, что компилятор именно так и поступает. Тем не менее, поменяв второе подвыражение на ((b*a)>0), компилятор принимает выражения за разные и генерирует умножение для обоих случаев, не смотря на то, что результат одинаков. Оптимизация арифметических операций Сложение и вычитание Применение инструкции LEA вместо ADD позволяет производить сумму 3х операндов (двух переменных и одной константы) за один такт. Трюк заключается в том представление ближних указателей эквивалентно их фактическому значению, поэтому результат, возвращенный LEA равен сумме ее операндов. При возможности Delphi производит такую замену. Деление Операция деления требует гораздо больше тактов процессора, нежели умножение, поэтому замена деления на умножение может значительно ускорить работу. Существуют формулы, позволяющие выполнять такое преобразование. Тем не менее, Delphi не использует такую оптимизацию. Деление на степень двойки можно заменять сдвигом вправо на n бит, но даже в этом случае получаем следующий код: mov esi,edi sar esi,1 jns +$03 adc esi, $00 Здесь учитывается особенность самой операции div – округление в большую сторону. Поэтому, если можно пренебрегать округлением, используйте c:=a shr 1 вместо с:=a div 2. Умножение Умножение на степень двойки можно заменять сдвигами битов. Delphi заменяет умножение сдвигами при умножении на 4,8,16 итд. При умножении на 2 производится суммированием переменной с собой. Умножать на 3,5,6,7,8,10 и т. д. можно и без операции умножения – расписав выражение по формуле (a shl n)+a, где n – показатель степени двойки. Например, при умножении на 3 n=1. Delphi при возможности прибегает к этому трюку. Заметим, операнд LEA умеет умножать регистр на 2,4,8, что также при возможности используется компилятором. Например, умножение на 3 преобразуется в инструкцию lea esi, [ebx + ebx*2] Оптимизация case of Анализ скомпилированного кода показывает, что Delphi проводит утрамбовку дерева. Т.е. значения case сортируются и выбор нужного элемента производится при помощи двоичного поиска. В случае, если элементы case of выстраиваются в арифметической прогрессии, компилятор формирует таблицу переходов. Т.е. создается массив указателей с индексами элементов, поэтому выбор нужно элемента выполняется за одну итерацию независимо от количества элементов. Оптимизация циклов Разворачивание циклов – не производится. Разворачивание циклов весьма спорный момент в оптимизации, поэтому принять грамотное решение может только человек. Delphi не производит разворачивания ни больших, ни маленьких циклов. Слияние циклов – не производится. Если два цикла, следующие друг за другом имеют одинаковые границы итерационной переменной, разумно оба цикла объединить в один. Вынесение инвариантного кода за пределы цикла – не выносится. Наиболее распространенный недочет – условие цикла записывается как: for i:=0 to memo1.lines.count – 1 do... Delphi будет при каждой итерации вызывать метод count, вычитать из результата 1 и потом уже сверять. Настоятельно рекомендуется переписывать подобный код как lin := .lines.count – 1; for i:=0 to lin do... Весь код VCL написан с нарушением этого правила. Очевидно, что проще подобного рода оптимизацию встроить в компилятор, нежели переписывать VCL :) Замена циклов с предусловием на циклы с постусловием – производится. Циклы с постусловием имеют главное преимущество над другими видами циклов (с предусловием и с условием в середине) – они содержат всего одно ветвление. Delphi производит такую замену. Замена инкремента на декремент – не производится. Более того, даже декрементный цикл компилируется в неоптимальный код, т.к. не используется флаг ZF. Вместо этого происходит сравнивание значения регистра с 0. Удаление ветвлений – не производится. Вывод:
![]() Литература 1. Касперски К. Техника оптимизации программ. Эффективное использование памяти. – СПб.:БХВ-Петербург, 2003. – 464 с.: ил. |
|||
![]() |
Cказали cпасибо: |
![]() |
Опции темы | Поиск в этой теме |
|
|
![]() |
||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
[Инструкция] Шпаргалка css. | Ghost | CSS и HTML | 6 | 06.01.2012 14:49 |