Как работает этот код для получения младшей битовой позиции? - PullRequest
2 голосов
/ 22 января 2011
unsigned GetLowestBitPos(unsigned value)
{
   double d = value ^ (value - !!value); 
   return (((int*)&d)[1]>>20)-1023; // This is what I really need help understanding. 
}

Мне кажется, что код переводит double в указатель на целое число.Я не уверен, для чего используется [1].Тогда похоже, что мы сдвигаемся на 20 бит вправо

Буду признателен за любую помощь по этому коду.Я давно программировал на C ++, и я пытаюсь написать логику для программируемого логического контроллера (ПЛК), чтобы сделать то же самое, если это возможно.

Спасибо за любую помощь

1 Ответ

6 голосов
/ 22 января 2011

Давайте сделаем один шаг за раз. Во-первых:

double d = value ^ (value - !!value);

Если value = 0, то это означает 0 ^ (0 - 0), поэтому d равно 0. Если value != 0, то это оценивается как значение ^ (значение - 1). Это приводит к установке младшего бита и младших нулевых битов в единицу, а всех остальных битов в ноль. например:

value = 010100100
d     = 000000111

Это происходит потому, что (value - 1) совпадает с value, за исключением того, что младшая строка нулевых битов становится единицей, а следующий бит становится нулем из-за переноса

value     = 010100100
value - 1 = 010100011
XOR value = 000000111

В любом случае, d загружается со значением с плавающей запятой этого значения. Следующая строка:

return (((int*)&d)[1]>>20)-1023; 

Это извлекает показатель с плавающей запятой и добавляет обратно смещение. Обратите внимание, что это предполагает систему с прямым порядком байтов, такую ​​как x86; в системе с прямым порядком байтов вам нужно использовать [0]. Он также делает предположения о размере int с и doubles - в частности, он предполагает 32-разрядные целочисленные значения и 64-разрядные значения IEEE для двойных чисел.

Ключевым моментом здесь является то, что неденормированные значения IEEE с плавающей запятой (и 32-битное целое число в двоичном всегда будет неденормированным) в конечном итоге будут выглядеть немного как 1.xxxxxxxx * 2^(e-1023), где xxxxxxxx дробная составляющая, а e - показатель степени. Поскольку вы расположили интересующие вас биты как биты высшего порядка, экспонента соответствует искомому значению.

Тем не менее, вы, вероятно, не сможете использовать это на ПЛК - хотя это довольно умный взлом, он эффективен даже удаленно, если у вас есть аппаратный FPU; и даже в системах x86 встроенные целочисленные операции быстрее . В этом вопросе есть ряд других техник ; Вы, вероятно, сможете найти более быстрый там. Ваш ПЛК также может иметь встроенную операцию для выполнения этой операции в одной инструкции.

...