Есть ли в cpu инструкция по сдвигу и копированию, доступ к которой можно получить из c #? - PullRequest
6 голосов
/ 21 сентября 2011

Мне нужно взять 8-битное число на 64-битном процессоре и сдвинуть его вправо 8 раз. Каждый раз, когда я сдвигаю число, мне нужно сдвигать одно и то же 8-битное число позади него, чтобы я получал одно и то же 8-битное число, повторяющееся 8 раз. В итоге получается смещение, добавление 8, смещение, добавление 8 ... и т. Д., Что в итоге составляет более 40 циклов (поправьте меня, если я ошибаюсь).

Есть ли способ выполнить эту операцию (сдвига и копирования) за 1 цикл, чтобы в итоге я получил одно и то же значение?

long _value = 0;
byte _number = 7;
for (int i = 0; i < 8; i++) {
    _value = (_value << 8) + _number;
}

РЕДАКТИРОВАТЬ: я пытаюсь сравнить поток символов для обнаружения ключевых слов. Я не могу использовать string.contains, поскольку строковое значение может находиться за границей буфера. Кроме того, приложение должно работать на встроенном процессоре ARM, а также на настольных и серверных процессорах. Использование памяти и циклы процессора очень важны.

Ответы [ 3 ]

6 голосов
/ 21 сентября 2011

В настоящее время нет прямой связи между количеством выполненных инструкций и количеством циклов ЦП , необходимых для их выполнения. Вы также, кажется, предполагаете, что оператор в C # соответствует одной инструкции сборки / процессора, что также неверно.

Ваш код, кажется, правильно делает то, что говорит описание вашего алгоритма (обратите внимание, что long подписан, используйте ulong для поведения без знака).

Если вы хотите использовать специализированные расширения процессора (например, mmx, sse и т. Д.), Которые могут выполнять присваивание-добавление-назначение в одной инструкции, вам необходимо использовать код сборки. Но я не уверен, существует ли такая конкретная инструкция. Это может зависеть от типа вашего процессора.

Вы не можете использовать ассемблерный код напрямую вместе с c #, но вы можете использовать ассемблер вместе с c (либо в качестве связанного объектного файла используйте его для встроенной сборки). Скомпилированный c-код можно использовать из c # /. Net с interop .

Но первым и важным вопросом для вас должен быть: Чего вы пытаетесь достичь?

Я сомневаюсь, что производительность важна для вашего приложения, и даже если вы честно спросите себя, является ли c # лучшим языком для вашей цели.

4 голосов
/ 21 сентября 2011

Другая идея заключается в том, чтобы предварительно вычислить все для всех значений байта таблицы поиска.

var lu = new long[256];
// init
var n = 7;
var v = lu[n];

Обновление

Некоторые результаты тестов (в мс на 100000000 итераций):

  • Петля: 272
  • развернуто: 207
  • Небезопасно: 351
  • Поиск: 250
  • HenkH: 216

Развернутая версия:

long _value = 0;
byte _number = 7;

_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;

Небезопасная версия:

long _value = 0;
byte _number = 7;

byte* p = (byte*)&_value;

*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;

К сожалению, не выполняет: (

Поиск - это просто чтение массива.

Все скомпилировано для x64 / release.

3 голосов
/ 21 сентября 2011

Если вы хотите, чтобы он был быстрым, вы могли бы по крайней мере развернуть свой цикл:

ulong _value = 0;
byte _number = 7;

_value = _number;
_value = (_value <<  8) + _value;
_value = (_value << 16) + _value;
_value = (_value << 32) + _value;

Это также будет иметь меньше ветвей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...