Код сначала преобразует v таким способом, который является полностью нулевым, за исключением самого левого, который остается.Затем он определяет положение этого первого.
Сначала давайте посмотрим, как мы подавляем все единицы, кроме самого левого.
Предположим, что k - это позиция самого левого в v.. v = (vn-1, vn-2, .. vk + 1,1,0, .. 0).
-v - число, добавленное к v, даст 0 (на самом деле это дает 2^ n, но бит 2 ^ n игнорируется, если мы сохраняем только n младших значащих бит).
Какое значение должно быть в -v, чтобы v + -v = 0?
очевидно, что биты k-1..0 в -k должны быть равны 0, чтобы при добавлении к завершающим нулям в v они давали ноль.
бит k долженбыть в 1. Добавленный к тому в vk, это даст ноль, и перенос в единицу в заказе k + 1
бит k + 1 из -v будет добавлен к vk+1 и к переносу, сгенерированному на шаге k.Это должно быть логическое дополнение vk + 1.Таким образом, независимо от значения vk + 1, у нас будет 1 + 0 + 1, если vk + 1 = 0 (или 1 + 1 + 0, если vk + 1 = 1), и результат будет 0 в порядке k + 1 с переносомгенерируется в порядке k + 2.
Это похоже на биты n-1..k + 2, и все они должны быть логическим дополнением соответствующего бита в v.
Следовательно, мы получаем известный результат, что для получения -v необходимо
оставить без изменений все конечные нули v
оставить без изменений самый левый из v
дополнить все остальные биты.
Если мы вычислим v & -v, у нас есть
v vn-1 vn-2 ... vk+1 1 0 0 ... 0
-v & ~vn-1 ~vn-2 ... ~vk+1 1 0 0 ... 0
v&-v 0 0 ... 0 1 0 0 ... 0
Так что v & -v держит только самый левый в v.
Чтобы найти местоположение первого, посмотрите код:
if (v) c--; // no 1 in result? -> 32 trailing zeros.
// Otherwise it will be in range c..0=31..0
if (v & 0x0000FFFF) c -= 16; // If there is a one in left most part of v the range
// of possible values for the location of this one
// will be 15..0.
// Otherwise, range must 31..16
// remaining range is c..c-15
if (v & 0x00FF00FF) c -= 8; // if there is one in either byte 0 (c=15) or byte 2 (c=31),
// the one is in the lower part of range.
// So we must substract 8 to boundaries of range.
// Other wise, the one is in the upper part.
// Possible range of positions of v is now c..c-7
if (v & 0x0F0F0F0F) c -= 4; // do the same for the other bits.
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;