Re: эффективность
От: Кодт Россия  
Дата: 16.11.03 11:15
Оценка:
Здравствуйте, фонарь, Вы писали:

Ф>что можно сказать по поводу такого алгоритма

Ф>
Ф>a -= b;   
Ф>b += a;   
Ф>a = b - a;
Ф>

Ф>против обычной замены?

Поскольку у Intel x86 нет операций память-память, за исключением строковых (movsb и т.п.), то по-любому возникнет потребность в промежуточном регистре.

extern void swap1(unsigned int& a, unsigned int& b)
{
  unsigned int x = a;
  a = b;
  b = x;

  // реконструкция ассемблерного кода (*1*)
  unsigned int x = a; // *2*
  unsigned int y = b;
  a = y;
  b = x;
}

extern void swap2(unsigned int& a, unsigned int& b)
{
  a -= b;
  b += a;
  a -= b;

  // реконструкция
  unsigned int x = a;
  unsigned int y = b;
  x -= y;
  a = x; // *3*
  y += x;
  b = y;
  x -= y;
  a = x;
}

extern unsigned int p = 100, q = 200;

int main()
{
  swap1(p,q);
  swap2(p,q);
  
  return 0;
}

*1* — получить ассемблерный код можно, запустив cl -Ox -Fa test.cpp
(-Ox — оптимизировать все).
Реконструировал вручную. Все-таки С выразительнее ассемблера

*2* — x,y — регистры. В ассемблерном листинге видно, что требуются 4 регистра: адрес a, адрес b (переданные параметры), x, y. Поскольку конвенция предполагает несохранение только трех — eax,ecx,edx, то четвертый — esi — сохраняется в стеке (push esi / pop esi).

*3* — не знаю, зачем пишется промежуточное значение a. Без этой строки вполне можно обойтись. Тем не менее...

Итого
* swap1 имеет 2 чтения и 2 записи в память.
* swap2 — 2 чтения, 3(2) записи и 3 арифметических операции регистр-регистр.
* Если бы swap2 использовал арифметику память-регистр, то ему пришлось бы неоднократно читать значения из памяти (что там получилось?). Естественно, это было бы еще медленнее.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.