Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Оптимальные конструкции языка.

241
13 июня 2006 года
Sanila_san
1.6K / / 07.06.2005
Перечитал вот этот пост и подумал, насколько вообще оптимальна конструкция case ... of в сравнении с тем же циклом. Понятно, что в какие-то моменты без неё не обойтись, а когда стоит выбор, то насколько такая конструкция будет оптимальной?
15K
14 июня 2006 года
foo
33 / / 03.06.2006
ну насколько... все примеры приведённые там, скомпилируются примерно в одно и тоже. А, вообще, замеряй по времени. возьми строчку длиной в пару метров и замеряй.
241
14 июня 2006 года
Sanila_san
1.6K / / 07.06.2005
Цитата:
возьми строчку длиной в пару метров и замеряй.

Где-то на RSDN встречал реализацию этого совета. :)

Получается, что приоритет за красотой конструкции, нежели за красотой машинного кода. Любопытно нас развратили быстрые процессоры.:) Просто у меня на работе комп на редкость тормозной, вот я и задумался о культуре бытия. Спасибо за высказывания. :)

10
14 июня 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=Sanila_san]Получается, что приоритет за красотой конструкции, нежели за красотой машинного кода. Любопытно нас развратили быстрые процессоры.:)[/QUOTE]
Сам-то понял, что сказал? Где связь между конструкциями ЯВУ, машинным кодом и скоростью процессора? Не вижу.
350
14 июня 2006 года
cheburator
589 / / 01.06.2006
[QUOTE=Sanila_san]...и подумал, насколько вообще оптимальна конструкция case ... of...[/QUOTE]
Насчет аналога в С++ (switch...case...).
Где-то читал (кажется, в каком-то стареньком учебнике по С++), что в определенных случаях компилятор реализует этот оператор через машинную команду xlat, что в общем-то работает значительно быстрее десятка if-ов.
241
14 июня 2006 года
Sanila_san
1.6K / / 07.06.2005
[QUOTE=Freeman]Где связь между конструкциями ЯВУ, машинным кодом и скоростью процессора? Не вижу.[/QUOTE]

Я вижу такую связь. Конструкции ЯВУ транслируются в конечном итоге в машинный код, исполняемый процессором. Грубо говоря, так и есть на деле. Отсюда вывод: определённые конструкции ЯВУ транслируются в определённые конструкции машинного кода, а уж они исполняются с разной скоростью. Другое дело, что есть некий предел времени выполнения, меньше которого нет никакого значения, сколько времени будет исполняться тот или иной алгоритм. Если оптимизированная конструкция работает, скажем, 1,4 секунды, а не очень оптимизированная - 1,8 секунды, то конечный пользователь не будет париться по этому поводу.
10
14 июня 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=cheburator]Где-то читал (кажется, в каком-то стареньком учебнике по С++), что в определенных случаях компилятор реализует этот оператор через машинную команду xlat, что в общем-то работает значительно быстрее десятка if-ов.[/QUOTE]
Это проблемы конкретного компилятора, не имеющие отношения к языку как синтаксической и семантической сущности.

[QUOTE=Sanila_san]Отсюда вывод: определённые конструкции ЯВУ транслируются в определённые конструкции машинного кода, а уж они исполняются с разной скоростью.[/QUOTE]
Вывод неочевиден, как и определенность конструкций. ЯВУ на то и ЯВУ, чтобы быть отвязанным от архитектуры конкретного процессора. Скорость выполнения - задача оптимизации кода, т. е. внешняя по отношению к языку программирования.
350
14 июня 2006 года
cheburator
589 / / 01.06.2006
[QUOTE=Freeman]Это проблемы конкретного компилятора, не имеющие отношения к языку как синтаксической и семантической сущности.
[/QUOTE]
Вопрос стоял об оптимальности (под которой в данном контексте я понимаю быстродействие). Т. е. я конкретно ответил на конкретный вопрос.
10
14 июня 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=cheburator]Вопрос стоял об оптимальности (под которой в данном контексте я понимаю быстродействие). Т. е. я конкретно ответил на конкретный вопрос.[/QUOTE]
Конкретно ответил на конкретный вопрос без упоминания контекста. Такой ответ автоматически становится абстрактным и потому неверным.

В приложении к конретному компилятору эффективность заключается в использовании соответствующей инструкции процессора как для формирования цикла, так и множественного ветвления.

В приложении к конкретной платформе эффективностью является наличие инструкции цикла и/или множественного ветвления.

Примеры где?
15K
14 июня 2006 года
foo
33 / / 03.06.2006
[QUOTE=Freeman]Это проблемы конкретного компилятора, не имеющие отношения к языку как синтаксической и семантической сущности.


Вывод неочевиден, как и определенность конструкций. ЯВУ на то и ЯВУ, чтобы быть отвязанным от архитектуры конкретного процессора. Скорость выполнения - задача оптимизации кода, т. е. внешняя по отношению к языку программирования.[/QUOTE]
как бы так сказать... если говорить про такие языки как Prolog, Haskell, то ты прав на все сто.
Но разговор идёт о языках типа C/C++/Pascal, а это совсем другое дело. К конкретной архитектуре можно и не привязываться, но есть общие принципы, выполняющиеся на _всех_ архитектурах. Даже не на всех, а на классе процессоров, которые рассматриваются как минимальные требования к программе.

Да и вообще, первая фраза, про проблемы компилятора, не верна в принципе. Когда я пишу на Haskell, не думая про оптимальность, то это просто потому, что я уже понял насколько синтаксис haskell'а и его абстракции позволяют компилятору оптимизировать код. А при написании программы на C/C++, если я не буду думать о том во что выльеться код после компиляции в asm, то я рискую получить неоправданно большую/тормозную программу. Даже если на верхнем уровне всё оптимизировано качественно. То есть выбраны алгоритмы и структуры данных, лучшим образом подходящие задаче.

И наконец, возвращаясь к данному случаю. Может ли компилятор, например, Delphi оптимизировать
 
Код:
if val in (0 ... 8) then
в просто две проверки, которые на паскале можно записать так:
 
Код:
if val >= 0 and val <= 8
?
А если зайдёт речь о
 
Код:
if val in (0, 2, 4, 6, 8, 10, 12, 14, 16)
будет ли это оптимизировано в
 
Код:
if not (val & 1)
(звиняйте за & -- не знаю как-там в паскале выглядит оператор побитового "и")?
Если нет, то код будет выполняться раза в три-четыре медленнее, как минимум.
Значит, всё-таки, надо знать границы возможностей компилятора.
10
14 июня 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=Sanila_san]Перечитал вот этот пост и подумал, насколько вообще оптимальна конструкция case ... of в сравнении с тем же циклом. [/QUOTE]
Все тесты проводились на Delphi 2006.

Код:
procedure UsingCase(var S: string);
var
  I: Integer;
begin
  for I  :=  1 to Length(S) do
  case S of
   '0': S := '1';
   '1': S := '2';
   '2': S := '3';
   '3': S := '4';
   '4': S := '5';
   '5': S := '6';
   '6': S := '7';
   '7': S := '8';
   '8': S := '9';
   '9': S := '0';
  end;
end;


Код:
Project1.dpr.11: begin
00408AF4 53               push ebx
00408AF5 56               push esi
00408AF6 57               push edi
00408AF7 51               push ecx
00408AF8 8BF8             mov edi,eax
Project1.dpr.12: for I  :=  1 to Length(S) do
00408AFA 8B07             mov eax,[edi]
00408AFC 890424           mov [esp],eax
00408AFF 8B0424           mov eax,[esp]
00408B02 85C0             test eax,eax
00408B04 7405             jz $00408b0b
00408B06 83E804           sub eax,$04
00408B09 8B00             mov eax,[eax]
00408B0B 8BF0             mov esi,eax
00408B0D 85F6             test esi,esi
00408B0F 0F8ED9000000     jle $00408bee
00408B15 BB01000000       mov ebx,$00000001
Project1.dpr.13: case S of
00408B1A 8B07             mov eax,[edi]
00408B1C 0FB64418FF       movzx eax,[eax+ebx-$01]
00408B21 83C0D0           add eax,-$30
00408B24 83F809           cmp eax,$09
00408B27 0F87B9000000     jnbe $00408be6
00408B2D FF2485348B4000   jmp dword ptr [eax*4+$408b34]
00408B34 5C               pop esp
00408B35 8B4000           mov eax,[eax+$00]
00408B38 6A8B             push $8b
00408B3A 40               inc eax
00408B3B 00788B           add [eax-$75],bh
00408B3E 40               inc eax
00408B3F 00868B400094     add [esi-$6bffbf75],al
00408B45 8B4000           mov eax,[eax+$00]
00408B48 A28B4000B0       mov [$b000408b],al
00408B4D 8B4000           mov eax,[eax+$00]
00408B50 BE8B4000CC       mov esi,$cc00408b
00408B55 8B4000           mov eax,[eax+$00]
00408B58 DA8B40008BC7     fimul dword ptr [ebx-$3874ffc0]
00408B5E E8ADBCFFFF       call @UniqueStringA
00408B63 C64418FF31       mov byte ptr [eax+ebx-$01],$31
00408B68 EB7C             jmp $00408be6
Project1.dpr.15: '1': S := '2';
00408B6A 8BC7             mov eax,edi
00408B6C E89FBCFFFF       call @UniqueStringA
00408B71 C64418FF32       mov byte ptr [eax+ebx-$01],$32
00408B76 EB6E             jmp $00408be6
Project1.dpr.16: '2': S := '3';
00408B78 8BC7             mov eax,edi
00408B7A E891BCFFFF       call @UniqueStringA
00408B7F C64418FF33       mov byte ptr [eax+ebx-$01],$33
00408B84 EB60             jmp $00408be6
Project1.dpr.17: '3': S := '4';
00408B86 8BC7             mov eax,edi
00408B88 E883BCFFFF       call @UniqueStringA
00408B8D C64418FF34       mov byte ptr [eax+ebx-$01],$34
00408B92 EB52             jmp $00408be6
Project1.dpr.18: '4': S := '5';
00408B94 8BC7             mov eax,edi
00408B96 E875BCFFFF       call @UniqueStringA
00408B9B C64418FF35       mov byte ptr [eax+ebx-$01],$35
00408BA0 EB44             jmp $00408be6
Project1.dpr.19: '5': S := '6';
00408BA2 8BC7             mov eax,edi
00408BA4 E867BCFFFF       call @UniqueStringA
00408BA9 C64418FF36       mov byte ptr [eax+ebx-$01],$36
00408BAE EB36             jmp $00408be6
Project1.dpr.20: '6': S := '7';
00408BB0 8BC7             mov eax,edi
00408BB2 E859BCFFFF       call @UniqueStringA
00408BB7 C64418FF37       mov byte ptr [eax+ebx-$01],$37
00408BBC EB28             jmp $00408be6
Project1.dpr.21: '7': S := '8';
00408BBE 8BC7             mov eax,edi
00408BC0 E84BBCFFFF       call @UniqueStringA
00408BC5 C64418FF38       mov byte ptr [eax+ebx-$01],$38
00408BCA EB1A             jmp $00408be6
Project1.dpr.22: '8': S := '9';
00408BCC 8BC7             mov eax,edi
00408BCE E83DBCFFFF       call @UniqueStringA
00408BD3 C64418FF39       mov byte ptr [eax+ebx-$01],$39
00408BD8 EB0C             jmp $00408be6
Project1.dpr.23: '9': S := '0';
00408BDA 8BC7             mov eax,edi
00408BDC E82FBCFFFF       call @UniqueStringA
00408BE1 C64418FF30       mov byte ptr [eax+ebx-$01],$30
Project1.dpr.24: end;
00408BE6 43               inc ebx
Project1.dpr.12: for I  :=  1 to Length(S) do
00408BE7 4E               dec esi
00408BE8 0F852CFFFFFF     jnz $00408b1a
Project1.dpr.25: end;
00408BEE 5A               pop edx
00408BEF 5F               pop edi
00408BF0 5E               pop esi
00408BF1 5B               pop ebx
00408BF2 C3               ret


 
Код:
procedure UsingFor(var S: string);
var
  I: Integer;
begin
  for I := 1 to Length(S) do
    if S = '9' then
      S := '0'
    else
      S := Chr(Ord(S) + 1);
end;


Код:
Project1.dpr.30: begin
00408BF4 53               push ebx
00408BF5 56               push esi
00408BF6 57               push edi
00408BF7 55               push ebp
00408BF8 51               push ecx
00408BF9 8BF0             mov esi,eax
Project1.dpr.31: for I := 1 to Length(S) do
00408BFB 8B06             mov eax,[esi]
00408BFD 890424           mov [esp],eax
00408C00 8B0424           mov eax,[esp]
00408C03 85C0             test eax,eax
00408C05 7405             jz $00408c0c
00408C07 83E804           sub eax,$04
00408C0A 8B00             mov eax,[eax]
00408C0C 8BF8             mov edi,eax
00408C0E 85FF             test edi,edi
00408C10 7E32             jle $00408c44
00408C12 BD01000000       mov ebp,$00000001
Project1.dpr.32: if S = '9' then
00408C17 8B06             mov eax,[esi]
00408C19 0FB65C28FF       movzx ebx,[eax+ebp-$01]
00408C1E 80FB39           cmp bl,$39
00408C21 750E             jnz $00408c31
Project1.dpr.33: S := '0'
00408C23 8BC6             mov eax,esi
00408C25 E8E6BBFFFF       call @UniqueStringA
00408C2A C64428FF30       mov byte ptr [eax+ebp-$01],$30
00408C2F EB0F             jmp $00408c40
Project1.dpr.35: S := Chr(Ord(S) + 1);
00408C31 8BC6             mov eax,esi
00408C33 E8D8BBFFFF       call @UniqueStringA
00408C38 0FB6D3           movzx edx,bl
00408C3B 42               inc edx
00408C3C 885428FF         mov [eax+ebp-$01],dl
00408C40 45               inc ebp
Project1.dpr.31: for I := 1 to Length(S) do
00408C41 4F               dec edi
00408C42 75D3             jnz $00408c17
Project1.dpr.36: end;
00408C44 5A               pop edx
00408C45 5D               pop ebp
00408C46 5F               pop edi
00408C47 5E               pop esi
00408C48 5B               pop ebx
00408C49 C3               ret
00408C4A 8BC0             mov eax,eax


 
Код:
procedure UsingMod(var S: string);
var
  I: Integer;
begin
  for I := 1 to Length(S) do
    S := Chr((Ord(S) + 1 - Ord('0')) mod 10 + Ord('0'));
end;


Код:
Project1.dpr.41: begin
00408C4C 53               push ebx
00408C4D 56               push esi
00408C4E 57               push edi
00408C4F 51               push ecx
00408C50 8BF8             mov edi,eax
Project1.dpr.42: for I := 1 to Length(S) do
00408C52 8B07             mov eax,[edi]
00408C54 890424           mov [esp],eax
00408C57 8B0424           mov eax,[esp]
00408C5A 85C0             test eax,eax
00408C5C 7405             jz $00408c63
00408C5E 83E804           sub eax,$04
00408C61 8B00             mov eax,[eax]
00408C63 8BF0             mov esi,eax
00408C65 85F6             test esi,esi
00408C67 7E2E             jle $00408c97
00408C69 BB01000000       mov ebx,$00000001
Project1.dpr.43: S := Chr((Ord(S) + 1 - Ord('0')) mod 10 + Ord('0'));
00408C6E 8BC7             mov eax,edi
00408C70 E89BBBFFFF       call @UniqueStringA
00408C75 8D4418FF         lea eax,[eax+ebx-$01]
00408C79 50               push eax
00408C7A 8B07             mov eax,[edi]
00408C7C 0FB64418FF       movzx eax,[eax+ebx-$01]
00408C81 40               inc eax
00408C82 83E830           sub eax,$30
00408C85 B90A000000       mov ecx,$0000000a
00408C8A 99               cdq
00408C8B F7F9             idiv ecx
00408C8D 83C230           add edx,$30
00408C90 58               pop eax
00408C91 8810             mov [eax],dl
00408C93 43               inc ebx
Project1.dpr.42: for I := 1 to Length(S) do
00408C94 4E               dec esi
00408C95 75D7             jnz $00408c6e
Project1.dpr.44: end;
00408C97 5A               pop edx
00408C98 5F               pop edi
00408C99 5E               pop esi
00408C9A 5B               pop ebx
00408C9B C3               ret
10
14 июня 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=foo]Может ли компилятор, например, Delphi оптимизировать
 
Код:
if val in (0 ... 8) then
в просто две проверки, которые на паскале можно записать так:
 
Код:
if val >= 0 and val <= 8
?
А если зайдёт речь о
 
Код:
if val in (0, 2, 4, 6, 8, 10, 12, 14, 16)
будет ли это оптимизировано в
 
Код:
if not (val & 1)
[/QUOTE]

 
Код:
function Opt1(Val: Integer): Boolean;
begin
  if Val in [0..8] then
    Result := True
  else
    Result := False;
end;


 
Код:
Project1.dpr.48: if Val in [0..8] then
00408C9C 83E809           sub eax,$09
00408C9F 7303             jnb $00408ca4
Project1.dpr.49: Result := True
00408CA1 B001             mov al,$01
00408CA3 C3               ret
Project1.dpr.51: Result := False;
00408CA4 33C0             xor eax,eax
Project1.dpr.52: end;
00408CA6 C3               ret


 
Код:
function Opt2(Val: Integer): Boolean;
begin
  if Val in [0, 2, 4, 6, 8, 10, 12, 14, 16] then
    Result := True
  else
    Result := False;
end;


Код:
Project1.dpr.56: if Val in [0, 2, 4, 6, 8, 10, 12, 14, 16] then
00408CA8 83F81F           cmp eax,$1f
00408CAB 7707             jnbe $00408cb4
00408CAD 0FA305BC8C4000   bt [$00408cbc],eax
00408CB4 7303             jnb $00408cb9
Project1.dpr.57: Result := True
00408CB6 B001             mov al,$01
00408CB8 C3               ret
Project1.dpr.59: Result := False;
00408CB9 33C0             xor eax,eax
Project1.dpr.60: end;
00408CBB C3               ret


 
Код:
function OptByFreeman(Val: Integer): Boolean;
begin
  Result := Val in [0..8];
end;


 
Код:
Project1.dpr.64: Result := Val in [0..8];
00408CC0 83E809           sub eax,$09
00408CC3 0F92C0           setb al
Project1.dpr.65: end;
00408CC6 C3               ret
241
15 июня 2006 года
Sanila_san
1.6K / / 07.06.2005
Любопытно. последний посто говорит о том, что всё-таки оптимальные конструкции языка существуют.

Цитата:
ЯВУ на то и ЯВУ, чтобы быть отвязанным от архитектуры конкретного процессора. Скорость выполнения - задача оптимизации кода, т. е. внешняя по отношению к языку программирования.



Согласен. Вообще я, когда говорил об отображении кода на ЯВУ в код на asm или машинный, я предполагал, что правила этого отображения для конкретного компилятора постоянны. ИМХО, предположение разумное, если я в каком-то проекте поменял одну конструкцию на другую.

10
15 июня 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=Sanila_san]Вообще я, когда говорил об отображении кода на ЯВУ в код на asm или машинный, я предполагал, что правила этого отображения для конкретного компилятора постоянны.[/QUOTE]
Правила постоянны только для конкретного случая, даже в пределах одного компилятора и платформы. Если в примерах с case AnsiString заменить на PChar или вообще делать case по целочисленным переменным, код изменится очень сильно - будет похоже на пример с in.

Поэтому, разговоры о "полезности" или "оптимальности" определенных конструкций ЯВУ вне конкретного контекста бессмысленны и вредны.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог