Являются ли Thens быстрее, чем умножение и присваивание? - PullRequest
6 голосов
/ 26 октября 2010

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

if blah then
    number = number + 2^n
end if

Будет ли оценка быстрее:

number = number + blah*2^n?

Что также вызывает вопрос, можете ли вы умножить логическое значение на целое число (хотя я не уверен, что тип, возвращаемый из 2 ^ n, является целым числом или без знака ... и т. Д.)?(Я работаю в Аде, но давайте попробуем обобщить это, может быть?)

РЕДАКТИРОВАТЬ: Извините, я должен уточнить, я смотрю на 2 в силу n, и я поставил c там, потому что мне было интереснодля моего собственного обучения в будущем, если я когда-нибудь столкнусь с этой проблемой в c и думаю, что на этих досках больше программистов c, чем Ada (я полагаю, и вы знаете, что это значит), однако моя текущая проблема заключается вязык ада, но вопрос должен быть достаточно независимым от языка (я надеюсь).

Ответы [ 10 ]

10 голосов
/ 26 октября 2010

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

Единственный способ узнать здесь - это проверить созданный ассемблер (обычно -S в качестве опции компилятора) и выполнить измерения.

5 голосов
/ 27 октября 2010

если мы говорим о C и бла не находится под вашим контролем, то просто сделайте это:

if(blah) number += (1<<n);

В C нет логического значения, и его не нужно, false равно нулю иЗначение true не равно нулю, поэтому вы не можете предполагать, что не ноль равен 1, что вам нужно для вашего решения, и вы не можете предполагать, что установлен какой-либо конкретный бит в бла, например:

number += (blah&1)<<n;

Будетне обязательно работать, потому что 0x2 или 0x4 или что-либо ненулевое с нулевым битом считается истинным.Как правило, вы найдете 0xFFF ... FFFF (минус один или все), использованные как true, но вы не можете полагаться на типичные значения.

Теперь, если вы полностью контролируете значение в бла, и сохраняетеэто строго 0 к ложному и 1 к истинному, тогда вы могли бы делать то, о чем вы спрашивали:

number += blah<<n;

И избежать возможности ветвления, дополнительного заполнения строки кэша и т. д.

Вернемся к общему случаю, хотя, взяв это общее решение:

unsigned int fun ( int blah, unsigned int n, unsigned int number )
{
    if(blah) number += (1<<n);
    return(number);
}

И компиляцию для двух самых популярных / используемых платформ:

    testl   %edi, %edi
    movl    %edx, %eax
    je  .L2
    movl    $1, %edx
    movl    %esi, %ecx
    sall    %cl, %edx
    addl    %edx, %eax
.L2:

В приведенном выше примере используется условная ветвь.

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

  cmp   r0,#0
  movne r3,#1
  addne r2,r2,r3,asl r1
  mov   r0,r2
  bx    lr

Могли бы сохранить инструкцию mov r0, r2, переставив аргументы в вызове функции, но это академично, вы не могли бы записать вызов функции на этом нормально.

РЕДАКТИРОВАТЬ:

Как предлагается:

unsigned int fun ( int blah, unsigned int n, unsigned int number )
{
    number += ((blah!=0)&1)<<n;
    return(number);
}
  subs  r0, r0, #0
  movne r0, #1
  add   r0, r2, r0, asl r1
  bx    lr

Конечно дешевле, икод выглядит хорошо, но я не буду делать предположенияns что результат blah! = 0, который равен нулю или что бы компилятор определил как true, всегда имеет установленный lsbit.Этот бит не обязательно должен быть установлен компилятором для генерации рабочего кода.Возможно, стандарты диктуют конкретное значение для истины.путем перестановки параметров функции число if (blah) + = ... также приведет к трем одиночным инструкциям часов и не будет иметь допущений.

EDIT2:

Глядя на то, что я понимаюбыть стандартом C99:

Операторы == (равно) и! = (не равно) аналогичны операторам отношения, за исключением их более низкого приоритета.Каждый из операторов выдает 1, если указанное отношение истинно, и 0, если оно ложно.

Что объясняет, почему вышеописанное редактирование работает и почему вы получаете movne r0, # 1, а не какое-то другое случайноеnumber.

Постер задавал вопрос относительно C, но также отметил, что ADA был текущим языком, с точки зрения независимости от языка, вы не должны принимать "функции", такие как функция C выше, и использовать if (бла) число = число + (1 <

5 голосов
/ 26 октября 2010

В Аде ...

Оригинальная формулировка:

if Blah then
  Number := Number + (2 ** N);
end if;

Альтернативная общая формулировка, предполагая, что Blah имеет тип Boolean, а Number и N - подходящих типов:

Number := Number + (Boolean'pos(Blah) * (2 ** N));

(Для N и Number пользовательских целочисленных типов или типов с плавающей запятой могут потребоваться подходящие определения и преобразования типов, ключевым моментом здесь является конструкция Boolean'pos(), которая, как гарантирует Ада, даст вам 0 или 1 для предопределенного логического типа.)

Что касается того, быстрее это или нет, я согласен с @Cthutu:

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

4 голосов
/ 26 октября 2010

В C, относительно бла * 2 ^ n: Есть ли у вас основания полагать, что бла принимает значения 0 и 1? Язык только обещает, что 0 <-> FALSE и (все остальное) <-> TRUE. C позволяет умножить «логическое» временное значение на другое число, но результат не определяется, за исключением того, что в результате = 0 <=> значение bool было ложным или число было равно нулю.

В Ada относительно бла * 2 ^ n: язык не определяет оператор умножения для типа Boolean. Таким образом, бла не может быть глупым и умножаться.

4 голосов
/ 26 октября 2010

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

number += (blah ? 2^n : 0);

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

1 голос
/ 01 августа 2017

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

n th степень 2 может быть вычислена с помощью оператора << как 1 << nпри условии, что n меньше числа битов значения в int.

Если blah является логическим , а именно int со значением 0 или 1, ваш фрагмент кода может быть записан:

number += blah << n;

Если blah - это любой скалярный тип, который можно проверить на его значение истинности как if (blah), выражение будет немного более сложным:

number += !!blah << n;

, что эквивалентно number += (blah != 0) << n;

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

1 голос
/ 26 октября 2010

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

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

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

1 голос
/ 26 октября 2010

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

0 голосов
/ 01 августа 2017

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

@Test
public void manual_time_trial()
{
    Date beforeIfElse = new Date();
    if_else_test();
    Date afterIfElse = new Date();
    long ifElseDifference = afterIfElse.getTime() - beforeIfElse.getTime();
    System.out.println("If-Else Diff: " + ifElseDifference);

    Date beforeMultiplication = new Date();
    multiplication_test();
    Date afterMultiplication = new Date();
    long multiplicationDifference = afterMultiplication.getTime() - beforeMultiplication.getTime();
    System.out.println("Mult Diff   : " + multiplicationDifference);

}

private static long loopFor = 100000000000L;
private static short x = 200;
private static short y = 195;
private static int z;

private static void if_else_test()
{
    short diff = (short) (y - x);
    for(long i = 0; i < loopFor; i++)
    {
        if (diff < 0)
        {
            z = -diff;
        }
        else
        {
            z = diff;
        }
    }
}

private static void multiplication_test()
{
    for(long i = 0; i < loopFor; i++)
    {
        short diff = (short) (y - x);
        z = diff * diff;
    }
}
0 голосов
/ 26 октября 2010

В любом случае вы не можете избежать ветвления (внутренне), поэтому не пытайтесь!

В

number = number + blah*2^n

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

В операторе «if then» оператор будет выполнять добавление и присваивание только тогда, когда бла истинно.

Короче говоря, ответ на ваш вопрос в этом случае "да".

...