Подтвердить что ты не робот

Является ли (var == true) быстрее, чем if (var!= False)?

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

EDIT: Спасибо тем, кто предоставил ответы.

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

И большое спасибо всем тем, кто оказал конструктивную критику. Я не знал о возможности указать, есть ли (var) до сих пор. Я почти уверен, что буду использовать его сейчас.;)

4b9b3361

Ответ 1

Во-первых: единственный способ ответить на вопрос о производительности - это измерить его. Попробуйте сами, и вы узнаете.

Что касается компилятора: напомню, что "если" - это только условное переключение. Когда у вас

if (x)
   Y();
else
   Z();
Q();

компилятор генерирует это как:

evaluate x
branch to LABEL1 if result was false
call Y
branch to LABEL2
LABEL1:
call Z
LABEL2:
call Q

или

evaluate !x
branch to LABEL1 if result was true

в зависимости от того, легче ли генерировать код, чтобы вызвать "нормальный" или "инвертированный" результат для любого "х". Например, если у вас есть if (a<=b), проще было бы сгенерировать его как (if !(a>b)). Или наоборот; это зависит от деталей компилируемого точного кода.

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

Ответ 2

Знаете ли вы, что на процессорах x86 более эффективно выполнять x ^= x, где x - это 32-разрядное целое число, чем это сделать x = 0? Это правда, и, конечно, имеет тот же результат. Следовательно, в любое время в коде можно видеть x = 0, его можно заменить на x ^= x и повысить эффективность.

Теперь вы когда-нибудь видели x ^= x в большом количестве кода?

Причина, по которой вы этого не сделали, заключается не только в том, что выигрыш в эффективности небольшой, а потому, что это именно то изменение, которое сделает компилятор (при компиляции на собственный код) или джиттер (при компиляции IL или аналогичных). Разберите некоторый код x86, и его необычно видеть эквивалент сборки x ^= x, хотя код, который был скомпилирован для этого, почти наверняка имел x = 0 или, может быть, нечто более сложное, например x = 4 >> 6 или x = 32 - y, где анализ код показывает, что y всегда будет содержать 32 в этой точке и т.д.

По этой причине, несмотря на то, что x ^= x, как известно, более эффективен, эффект единственного этого в огромном большинстве случаев будет заключаться в том, чтобы сделать код менее читаемым (единственное исключение будет заключаться в том, что в случае использования x ^= y в используемом алгоритме мы выполняли случай, когда x и y были здесь одинаковыми, в этом случае x ^= x сделает использование этого алгоритма более четким а x = 0 скроет его).

В 99,999999% процентов случаев то же самое относится к вашему примеру. В оставшихся 0.000001% случаях должно быть, но там разница в эффективности между каким-то странным видом оператора переопределяет и, который компилятор не может разрешить друг другу. Действительно, 0,000001% преувеличивает случай, и это просто упоминается, потому что я уверен, что если бы я достаточно старался, я мог бы написать что-то, где один был менее эффективным, чем другой. Обычно люди не пытаются это сделать.

Если вы когда-нибудь взглянете на свой собственный код в отражателе, вы, вероятно, найдете несколько случаев, когда он выглядит совсем иначе, чем код, который вы написали. Причина этого в том, что это обратное проектирование IL вашего кода, а не самого кода, и, действительно, одна вещь, которую вы часто найдете, это такие вещи, как if(var == true) или if(var != false), которые превращаются в if(var) или даже в if(!var) с блокировкой if и else.

Посмотрите глубже, и вы увидите, что еще больше изменений сделано в том, что существует более одного способа обмануть одного и того же кота. В частности, интересно посмотреть, как преобразования switch преобразуются в IL. иногда он превращается в эквивалент кучки операторов if-else if, и иногда он превращается в поиск в таблицу прыжков, которая может быть сделана, в зависимости от того, что казалось более эффективным в рассматриваемом случае.

Посмотрите еще глубже, и другие изменения будут сделаны, когда он скомпилируется в собственный код.

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

Ответ 3

Это ничего не изменит. Используя отражатель, вы можете видеть, что код:

private static void testVar(bool var)
{
    if (var == true)
    {
        Console.WriteLine("test");
    }

    if (var != false)
    {
        Console.WriteLine("test");
    }

    if (var)
    {
        Console.WriteLine("test");
    }
}

создает IL:

.method private hidebysig static void testVar(bool var) cil managed
{
  .maxstack 8
  L_0000: ldarg.0 
  L_0001: brfalse.s L_000d
  L_0003: ldstr "test"
  L_0008: call void [mscorlib]System.Console::WriteLine(string)
  L_000d: ldarg.0 
  L_000e: brfalse.s L_001a
  L_0010: ldstr "test"
  L_0015: call void [mscorlib]System.Console::WriteLine(string)
  L_001a: ldarg.0 
  L_001b: brfalse.s L_0027
  L_001d: ldstr "test"
  L_0022: call void [mscorlib]System.Console::WriteLine(string)
  L_0027: ret 
}

Итак, компилятор (в .Net 3.5) переводит все их в набор команд ldarg.0, brfalse.s.

Ответ 4

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

(используйте if (var) вместо этого, вам не нужен визуальный беспорядок сравнений.)

Ответ 5

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

Сборка (псевдо) будет либо:

test reg1, reg2
br.true somewhere
; code for false case

somewhere:
; code for true case

или

test reg1, reg2
br.false somewhere
; code for true case

somewhere:
; code for false case

Какой из этих вариантов компилятор не будет зависеть от того, пишете ли вы == true или != false. Скорее, это оптимизация, которую сделает компилятор на основе размера кода истинного и ложного кода и, возможно, некоторых других факторов.

Как и в остальном, код ядра Linux на самом деле пытается оптимизировать эти ветки, используя макросы LIKELY и UNLIKELY для своих условий if, поэтому я предполагаю, что это возможно для его ручного управления.

Ответ 6

Обычно используется правило: "Если вы знаете, что они делают то же самое, то компилятор тоже знает".

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

Следовательно, предположим, что они одинаково быстры, пока ваш профилировщик не скажет вам иначе.

Ответ 7

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

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

tl; dr не беспокоиться

Ответ 8

Остальные ответы на все хорошо, я просто хотел добавить:

Это не существенный вопрос, потому что он предполагает отношение 1:1 между обозначением и полученным IL или собственным кодом.

Нет. И это правда даже в С++ и даже в C. Вам нужно пройти весь путь до собственного кода, чтобы иметь такой вопрос.

Отредактировано для добавления:

Разработчики первого компилятора Fortran (около 1957 года) были удивлены в один прекрасный день, когда просматривали его результаты. Это был код, который явно не был прав (хотя это было); по сути, он принимал решения по оптимизации, которые явно не были правильны (хотя они были).

Мораль этой истории: компиляторы были более умны, чем люди более 50 лет. Не пытайтесь перехитрить их, если вы не готовы изучить их результаты и/или провести обширное тестирование производительности.

Ответ 9

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

Например, вы можете написать

if (!predicate)
    statement1;
else
    statement2;

и компилятор может испускать код, эквивалентный

if (predicate)
    statement2;
else
    statement1;

или наоборот.

Ответ 10

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

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

Можно предположить, что процессор может изменить флаги состояния при загрузке 'var'. Если это так, то если "var" равно 0, то флаг нуля может быть установлен, когда переменная загружается в регистр. С таким процессором явное сравнение с FALSE не требуется. Эквивалентный псевдокод сборки будет...

load 'var' into register
branch if zero or if not zero as appropriate

Используя этот же процессор, если вы должны были протестировать его против TRUE, псевдокод сборки будет...

load 'var' into register
compare that register to TRUE (a specific value)
branch if equal or if not equal as appropriate

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

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

if (var == TRUE)
if (var != FALSE)

и используйте одно из следующих значений для тестирования булевых типов...

if (var)
if (!var)