Давайте немного поближе посмотрим на memcpy
и, пока мы на нем, на «большой O» или нотацию Ландау.
Во-первых, большой-О. Как я уже говорил в другом месте, стоит запомнить определение большого O, которое заключается в том, что некоторая функция g(n) называется O(f(n)) когда существует константа k, для которой g(n) kf(n). Что делает константа, так это позволяет вам игнорировать мелкие детали в пользу важной части. Как все уже заметили, memcpy
из n байтов будут O(n) в большинстве случаев любой нормальной архитектуры, потому что независимо от того, что вам нужно переместить эти n em> байт, по одной порции за раз. Таким образом, можно было бы написать первую наивную реализацию memcpy
на C.
unsigned char *
memcpy(unsigned char * s1, unsigned char * s2, long size){
long ix;
for(ix=0; ix < size; ix++)
s1[ix] = s2[ix];
return s1;
}
На самом деле это O(n), и вы можете задаться вопросом, почему мы вообще возимся с библиотечной подпрограммой. однако особенность функций libc заключается в том, что они являются местом, где пишутся специфичные для платформы утилиты; если вы хотите оптимизировать архитектуру, это одно из мест, где вы можете это сделать. Таким образом, в зависимости от архитектуры могут существовать более эффективные варианты реализации; например, в архитектуре IBM 360 есть инструкция MOVL
, которая перемещает данные большими порциями, используя очень оптимизированный микрокод. Таким образом, вместо этого цикла реализация memcpy 360 может выглядеть примерно так:
LR 3,S1 LOAD S1 ADDR in Register 3
LR 4,S2
MOVL 3,4,SIZE
(Кстати, нет гарантий, что это правильный 360-градусный код, но он послужит иллюстрацией.) Эта реализация выглядит так, что вместо выполнения n шагов по циклу в качестве Код C сделал, он просто выполняет 3 инструкции.
Однако на самом деле происходит то, что он выполняет O(n) микро инструкций под прикрытием. Что отличается между ними, так это константа k; потому что микрокод намного быстрее, и поскольку в инструкциях всего три шага декодирования, он значительно быстрее, чем наивная версия, но все равно O(n) -- просто константа меньше.
И именно поэтому вы можете эффективно использовать memcpy
— он не асимптотически быстрее, но его реализация настолько быстра, насколько это возможно на этой конкретной архитектуре.
person
Charlie Martin
schedule
27.12.2008