Лучшая логика для этого побитового выражения? - PullRequest
1 голос
/ 04 января 2012

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

Например, если начальное смещение сегмента было 0x2000, а окончание было 0x3523, это означало бы, что он занимает два блока, 0x2000 и 0x3000. Он не занимает полных 0x2000 байтов в блоках данных, но считается, что он «занимает блок», когда находится внутри него. Моей первой мыслью было сделать:

( ( EndingOffset - StartingOffset ) + 0xFFF ) >> 0xC

Это эквивалент Math.Ceil((EndingOffset - StartingOffset) / 0x1000), но я новичок в побитовых операторах и мне нравится работать с ними.

В любом случае, логика была ошибочной, поскольку, и это тот случай, который меня понял, если начальное смещение 0x3D8A и конечное смещение 0x671D, разница между ними составляет 0x2993. Округлили это 0x3000, или три блока. Сегмент на самом деле занимает четыре, 0x3000, 0x4000, 0x5000 и 0x6000. Поэтому мой следующий поезд, и, к сожалению, мой последний, должен был вместо этого найти разницу между смещением первого блока, в котором находится сегмент, и смещением первого блока, в котором сегмент не находится.

С 0x3D8A и 0x671D это подводит меня к (0x7000 - 0x3000) >> 0xC, который успешно дает правильное количество блоков, 4. То, как я это написал, я хочу улучшить, а именно:

BlockSize = ((((OffsetEnd + 0xFFF) >> 12) + 1) - ((OffsetStart + 0xFFF) >> 12));

Я знаю, что слишком усложнил простую проблему, но я не могу понять, как написать ее лучше.

править: Это стыдно. Я не знаю, как я пришел к этому вместо

(((OffsetEnd + 0xFFF) >> 12) - (OffsetStart >> 12));

Тем не менее, кажется, не завершено.

edit 2: Извините, забыл упомянуть, что конечное смещение является исключительным, не включающим и является позицией после последнего байта сегмента, означающего:

(((OffsetEnd - 1 + 0xFFF) >> 12) - (OffsetStart >> 12));

править 3: Исходя из ответа Керека, я получаю:

BlockSize = 1 + (offsetEnd - 1 >> 12) - (offsetStart >> 12);

.. или, с учетом 0,

BlockSize = (offsetEnd - 1 >> 12) - (offsetStart >> 12);

edit 4: Забудь отсчет с нуля, я придерживаюсь:

BlockSize = 1 + (offsetEnd - 1 >> 12) - (offsetStart >> 12);

Ответы [ 2 ]

0 голосов
/ 04 января 2012

((EndingOffset - StartingOffset) + 0xFFF) >> 0xC + (StartingOffset & ~ (0xFFF)! = 0)

Это будет иметь краткое начало, которое у вас есть, и увидит, если StartingOffset падает награница блока или нет.Если это не так, добавьте 1.

0 голосов
/ 04 января 2012

Предполагая, что ваши диапазоны данных заданы как [начало, конец) , это довольно просто:

unsigned int start_block = start_offset / 0x1000;
unsigned int end_block = end_offset / 0x1000;

unsigned int number_of_blocks = end_block - start_block + (end_offset > start_offset && end_offset % 0x1000 > 0 ? 1 : 0);

Битный эквивалент / 0x1000 равен >> 12, я полагаю.

Ваши данные будут занимать диапазон блоков [start_block, end_block). Обратите внимание, что блок 0 равен [0x0000, 0x1000), блок 1 равен [0x1000, 0x2000) `и т. Д.

Как указывал @Ron, вам понадобится одно условие, чтобы определить, является ли последний ("один-последний") блок пустым, и увеличить число блоков на единицу в последнем случае.

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