2015-07-05 7 views
0

Jeffrey Stedfast предложил several functions that calculates the nearest power of 2. Одна из функций имеет код следующим образом:В чем смысл этого кода на C? [оценка короткого замыкания]

static uint32_t 
nearest_pow (uint32_t num) 
{ 
    uint32_t j, k; 
    (j = num & 0xFFFF0000) || (j = num); // What is this? 
    ... 
} 

Чтобы полностью понять код, я попытался изменить линию к:

j = num & 0xFFFF0000; 
    j = j | (j = num); 

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

В чем смысл (j = num & 0xFFFF0000) || (j = num);?

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

+0

Я, возможно, сэкономлю вам время и усилия, если вы спросите: «вам действительно нужно выполнить эту * конкретную реализацию с помощью бит-хаков на вашем языке»? Может быть, ваш язык имеет библиотечную функцию? Кроме того, разница между v2 и v4 не такая большая, но v4 имеет некоторые ограничения. Принесете ли вы что-нибудь от этого? Это не ответ на ваш вопрос, но полностью исключить эту реализацию можно было бы косвенным решением для [Проблема] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Drop

+0

@ Drop: На мой взгляд, функции, выполняющие базовые функции, должны быть реализованы с использованием самого быстрого подхода. Необходимость использования основных функций внутри цикла в миллион раз, вероятно, встретится в наши дни. Да, действительно, последний вариант имеет ограничения, но в определенных обстоятельствах ограничения потенциально желательны. Поэтому я буду использовать его в качестве варианта метода [Sean Eron Anderson] (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2). – Astaroth

ответ

1

|| является логическим или -оператором. Он имеет короткое замыкание, так что, если левая сторона истинна, правая сторона не оценивается (потому что результат логического или, как известно, уже прав с истинной левой стороны).

В этом случае он используется в обходном порядке для обеспечения резервного задания j = num, если первое назначение j = num & 0xFFFF0000 равно нулю («false»). Итак, сначала верхние два байта (маска 0xFFFF0000) num присвоены j. Если это ноль («ложь»), то есть верхние два байта не имеют никаких 1-битов, то num присваивается j.

Фактически это означает, что «назначить j верхние два байта num, если они не равны нулю, в противном случае назначить j нижние два байта из num».

+0

Большое вам спасибо. Я не знал, что раньше была оценка _short-circuit_ в C, и спасибо за объяснение деталей кода. – Astaroth

1
(j = num & 0xFFFF0000) || (j = num); 

В связи с оценкой короткого замыкания логического оператора ИЛИ, если j = num & 0xFFFF0000 не является 0 (значение TRUE), то j = num не будет оцениваться; иначе j = num будет оцениваться впоследствии.

Таким образом, вся семантика:

j = num & 0xFFFF0000; 
if (j != 0) { // no operation 
} else { 
    j = num; 
} 
+0

Неправильная операция. Подумайте об этом, что, если num - 0x10000, тогда ваше расширение будет иметь j = 0, тогда как исходный код будет иметь j = 0x10000 – slebetman

+0

@Arkku: Ah. ОК.Я пропустил это, потому что в моем сознании семантика не имеет условия 'else', вместо этого я думаю о семантике' || 'быть' if (! J) ..' – slebetman

+0

@timrau: На самом деле все ответы здесь заслуживают принять, но я должен выбрать только один ответ. Итак, +1. – Astaroth

1

Что такое значение (к = Num & 0xFFFF0000) || (j = num) ;?

Что-то формы a || b будет оценивать a, а затем оценить b только если a была ложной. Другими словами, j = num будет оцениваться только в том случае, если j = num & 0xFFFF0000 является ложным. Выражение считается ложным в C++, если он равен 0, так что это эквивалентно:

if ((j = num & 0xFFFF0000) == 0) { 
    j = num; 
} 

Или, разбитого друг от друга больше, могли бы сделать это еще яснее:

uint32_t masked = num & 0xFFFF0000; 
if (masked == 0) { 
    j = num; 
} else { 
    j = masked; 
} 
+0

На самом деле все ответы здесь заслуживают принятия, но я должен выбрать только один ответ. Итак, +1. – Astaroth

1
(j = num & 0xFFFF0000) || (j = num); 

и

j = num & 0xFFFF0000; 
j = j | (j = num); 

не эквивалентны, я не знаю, почему вы получите тот же результат.

В чем смысл (j = num & 0xFFFF0000) || (j = num) ;?

Прежде чем обсуждать, что это точно означает, что вы должны знать порядок оценочной logical or|| операции, которая слева направо. В C zero 0 означает boolean false и любое другое ненулевое значение означает boolean true. Теперь посмотрим на следующее выражение,

left || right 

left Если это true то right никогда не будет выполнена, right только выполняется тогда и только тогда, когда left ложно.

Вопрос остается, и в этом случае left будет ложным? В этом выражении:

(j = num & 0xFFFF0000) || (j = num); 

(j = num & 0xFFFF0000) будет ложным, если j присваивается 0 означает num & 0xFFFF0000 производить 0.

Так что если num & 0xFFFF0000 производят 0 то право выражения будет выполняться (j = num) и j наконец, обновленной num. Конец истории.

Теперь, что означает следующий код?

j = j | (j = num); 

это означает, назначить num в j и выполнять bitwise or| с предыдущим j и переназначить конечное значение в j.

+0

@rakeb_void: +1. На самом деле ваш ответ также заслуживает того, чтобы согласиться, но я должен выбрать только один ответ. – Astaroth

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

  • Нет связанных вопросов^_^