2013-07-28 2 views
-5

Я хочу знать, какой из этих фрагментов выполняется быстрее.Is (x <= y) или! (x> y) более эффективно?

Я обычно использую это выражение:

if(x <= y) 
    break; 

Но есть преимущество, чтобы использовать это?

if(!(x > y)) 
    break; 

Вот мои рассуждения. Я думаю, что первое утверждение на самом деле это:

if(x == y) 
    break; 
if(x < y) 
    break; 

Но я думаю, что второе утверждение только это:

if(!(x > y)) 
    break; 

Это приводит меня к мысли, что второе утверждение быстрее. Это правильно?

+0

Посмотрите на сборку из оптимизированной сборки. – Mat

+0

Если '<=' перегружен, он почти всегда реализуется как '! (X> y)'. – Rapptz

+0

Хорошо, тогда почему есть 'jle' и' jng'? Или это одна и та же инструкция? –

ответ

8

скомпилирован с использованием gcc -O3 -march=native -m64 -fomit-frame-pointer -S:

int f(int x, int y) { 
    if (x <= y) return 1; 
    return 0; 
} 

f: 
    xorl %eax, %eax 
    cmpl %edx, %ecx 
    setle %al 
    ret 

и

int f(int x, int y) { 
    if (!(x > y)) return 1; 
    return 0; 
} 

f: 
    xorl %eax, %eax 
    cmpl %edx, %ecx 
    setle %al 
    ret 

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

+0

с использованием '(a == b || a etam1024

1

Полагая х & у построены типы,

Вот мои рассуждения. Я думаю, что первое утверждение на самом деле это:

if(x == y) 
    if(x < y) 
     break; 

Это не верно. ЦПУ может выполнять операции <=. Не переустраивайте;)

1

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

Но если эти фрагменты будут интерпретироваться буквально, то в архитектуре x86 первая будет представлять собой одну операцию, так как набор инструкций процессора x86 содержит инструкции как для перехода по принципу «прыжок», так и для перехода в режим «переход», равны.

4

Очень маловероятно, что компилятор будет генерировать нечто отличное от другого. Практически все современные процессоры имеют операцию сравнения/ветвления greater or equal или less or equal, поэтому не должно быть причин для более сложного сравнения.

Заявление

if(x == y) 
     if (x < y) 
     break; 

не имеет никакого смысла. Либо x == y истинно, и в этом случае x < y не соответствует действительности. Или x == y является ложным, и вы не вводите второй, если вообще.

Очевидно, что если x и y это класс, то operator<= можно записать в виде:

operator<=(const A& x, const A& y) 
{ 
    if (x == y) return true; 
    return x < y; 
} 

Но это было бы довольно глупо, так как он точно так же может быть записано как:

operator<=(const A& x, const A& y) 
{ 
    return !(x > y); 
} 
+0

Я могу ошибаться, но имеет смысл обсуждать различия между детексом и вектором, чем пытаться выбрать один из этих двух вариантов, также, как правило, C++ оставляет много свободы для компилятора C++, этот вопрос - просто фитизм для код. Я разделяю видение, где все структуры данных и алгоритмы - все, что вам нужно для кодирования и сосредоточения внимания на создании программы, все остальное просто бессмысленно, ваш компилятор может сделать намного лучше, чем вы. – user2485710

+0

Лучше меня, или лучше оригинального плаката? ;) –

0

Есть 2 причины, почему вы должны использовать <=

  1. ЦП может выполнять операции для примитивов <=.

  2. Если классы имеют перегруженный оператор <=, то можно предположить, что он оптимизирован, чтобы сделать это лучше, чем if(!(x > y)) или, по крайней мере, равным ему. Поэтому, если он существует, используйте его. Кто-то приложил все усилия для его реализации по какой-то причине.

1

С точки зрения int (или короткого или длинного или любого другого), просто используйте x <= y, и компилятор должен его оптимизировать. Например, на x86-64:

cmpq %rax, %rcx 
    jg false 
#This is code to execute if (x <= y). 
# Code 
# ....... 
false: 
    #This is code to execute once the 
    # if statement is done or the condition 
    # resulted in a falsy value. 

Если у вас есть, если-нибудь заявление, есть две команды скачка: первый, если условие дает falsy значение, а второй находится в конце кода блок, когда условие дает истинное значение (поэтому он может пропустить код, используемый для блока else).

Обратите внимание, что я использовал инструкцию jg (jump if more than). У x86 и x86-64 оба имеют инструкцию jnle (jump if not less or or), но она делает то же самое (в конце концов, если x не меньше или равно y, тогда логически x должно быть больше чем у), но с точки зрения работы в АСМ имеет смысл инвертировать условие. Если бы условие не было инвертировано, вы бы перескочили вперед, чтобы выполнить код для оператора if, и отскочили назад, чтобы возобновить основной поток программы. Почему в двух прыжках, что вы можете сделать с одним?

BTW, я не являюсь гуру ASM. Однако, если вы немного поработаете с ним, это может помочь вам избежать вопросов, подобных этим, потому что компилятор должен оптимизировать ваше состояние (x <= y) до !(x > y) в любом случае, как я показал. Нет необходимости пытаться повторить угадывание своего компилятора. Сосредоточьтесь на обычной оптимизации, которую вы можете сделать, чтобы помочь компилятору оптимизировать ваш код, например, устранение условий, которые не нужно выполнять в первую очередь, а не тот материал, который он уже знает, как это сделать.

Смежные вопросы