Эффективность сравнения - PullRequest
       21

Эффективность сравнения

2 голосов
/ 16 сентября 2009

Что обычно быстрее:

if (num >= 10)

или

if (!(num < 10))

Ответы [ 3 ]

25 голосов
/ 16 сентября 2009

Компилятор, скорее всего, оптимизирует подобные вещи. Не беспокойтесь об этом, просто используйте код для ясности в этом случае.

Языки ассемблера часто имеют операции для >= и <=, которые имеют то же количество шагов, что и < и >. Например, с Motorola 68k , если вы хотите сравнить регистры данных %d0 и %d1 и ветвь, если %d0 больше или равно %d1, вы бы сказали что-то вроде :

cmp %d0, %d1  // compare %d0 and %d1, storing the result
              // in the condition code registers.
bge labelname // Branch to the given label name if the comparison
              // yielded "greater than or equal to" (hence bge)

Распространенной ошибкой считается, что a >= b означает, что компьютер будет выполнять две операции вместо одной из-за того, что "или" в "больше или равно".

11 голосов
/ 16 сентября 2009

Любой приличный компилятор оптимизирует эти два оператора в соответствии с одним и тем же базовым кодом. Фактически, он, скорее всего, сгенерирует точно такой же код для:

if (!(!(!(!(!(!(!(num < 10))))))))

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

  • если число больше или равно десяти.
  • если это не так, число меньше десяти.

Я считаю, что первый будет более ясным.

Фактически, просто тестируя с помощью "gcc -s", чтобы получить вывод на ассемблере, оба оператора генерируют следующий код:

cmpl $9,-8(%ebp) ; compare value with 9
jle .L3          ; branch if 9 or less.

Я полагаю, что вы тратите свое время на такие микрооптимизации, как вы, - вам гораздо эффективнее смотреть на такие вещи, как выбор алгоритма. Там, вероятно, будет гораздо большая отдача от инвестиций.

3 голосов
/ 16 сентября 2009

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

Во многих языках сравнение значения с плавающей запятой NaN возвращает false для всех сравнений, поэтому, если num = NaN, первое - false, а второе - true.

#include <iostream>
#include <limits>

int main ( ) {
    using namespace std;

    double num = numeric_limits<double>::quiet_NaN();

    cout << boolalpha;
    cout << "( num >= 10 )      " << ( num >= 10 ) << endl;
    cout << "( ! ( num < 10 ) ) " << ( ! ( num < 10 ) ) << endl;

    cout << endl;
}

выходы

( num >= 10 )      false
( ! ( num < 10 ) ) true

Таким образом, компилятор может использовать одну инструкцию для сравнения num и значения 10 в первом случае, но во втором может выдать вторую инструкцию, чтобы инвертировать результат сравнения. (или он может просто использовать ветвь, если ноль, а не ветвь, если не ноль, вы не можете сказать вообще)

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

...