Почему этот код с несколькими операторами "или" немного быстрее, чем использование таблицы поиска в Java? - PullRequest
9 голосов
/ 18 ноября 2008

Просматривая вопрос о микрооптимизации, который я задал вчера ( здесь ), я обнаружил нечто странное: оператор or в Java выполняется немного быстрее, чем поиск логическое значение в массиве логических значений.

В моих тестах при выполнении приведенных ниже алгоритмов на long значениях от 0 до 1 миллиарда alg1 работает примерно на 2% быстрее. (Я изменил порядок, в котором тестируются алгоритмы, и получаю те же результаты). Мой вопрос: Почему alg1 быстрее? Я бы ожидал, что alg2 будет немного быстрее, поскольку он использует таблицу поиска, тогда как alg1 должен выполнить 4 сравнения и 3 или операции для 75% входных данных.

private final static boolean alg1(long n)
{
  int h = (int)(n & 0xF);
  if(h == 0 || h == 1 || h == 4 || h == 9)
  {
    long tst = (long)Math.sqrt(n);
    return tst*tst == n;
  }  
  return false;

}

private final static boolean[] lookup = new boolean[16];
static
{
  lookup[0] = lookup[1] = lookup[4] = lookup[9] = true;
}
private final static boolean alg2(long n)
{
  if(lookup[(int)(n & 0xF)])
  {
    long tst = (long)Math.sqrt(n);
    return tst*tst == n;
  }
  else
    return false;
}

Если вам интересно, этот код проверяет, является ли число совершенным квадратом, и использует тот факт, что совершенные квадраты должны заканчиваться на 0, 1, 4 или 9 в шестнадцатеричном виде.

Ответы [ 5 ]

8 голосов
/ 18 ноября 2008

Загрузка некоторого случайного фрагмента данных, как правило, медленнее, чем небольшой не ветвящийся код.

Конечно, все зависит от архитектуры процессора. Ваш первый оператор if может быть реализован в виде четырех инструкций. Второму может потребоваться проверка нулевого указателя, проверка границ, а также загрузка и сравнение. Кроме того, больше кода означает больше времени компиляции и больше шансов для оптимизации каким-либо образом.

3 голосов
/ 18 ноября 2008

Я бы предположил , что проблема заключается в том, что проверка диапазона для массива и если поиск в массиве реализован как вызов метода. Это, конечно, затмило бы 4 прямые сравнения. Вы смотрели на байт-код?

1 голос
/ 20 ноября 2008

В текущем примере я согласен, что проверка границ - это, вероятно, то, что вас привлекает (почему JVM не оптимизирует это, мне не подходит - пример кода может быть детерминированно показан не переполненным ...

Еще одна возможность (особенно для больших таблиц поиска) - это задержка кэша ... Это зависит от размера регистров процессора и того, как JVM решит их использовать - но если байтовый массив не полностью хранится на процессоре, тогда вы увидите снижение производительности по сравнению с простым ИЛИ, когда массив загружается в ЦП для каждой проверки.

1 голос
/ 18 ноября 2008

Согласно этой статье доступ к элементам массива "в 2 или 3 раза дороже, чем доступ к элементам, не являющимся массивами". Ваш тест показывает, что разница может быть даже больше.

0 голосов
/ 19 ноября 2008

Это интересный кусок кода, но 2% - это действительно небольшая разница. Я не думаю, что вы можете сделать очень большой вывод из этого.

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