这个按位表达式有更好的逻辑

本文关键字:更好 表达式 | 更新日期: 2023-09-27 18:19:18

我正在编写一个处理使用哈希值的文件的程序。数据被分成长度为0x1000的块。我需要计算具有特定开始和结束偏移覆盖的段的块数量。

例如,如果段的起始偏移量为0x2000,结束偏移量为0x3523,则意味着它占用了两个块,0x2000和0x3000。它不会占用数据块中的全部0x2000字节,但是当它在一个块内时,它被认为是"占用一个块"。我的第一个想法是:

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

这相当于Math.Ceil((EndingOffset - StartingOffset) / 0x1000),但我是位运算符的新手,喜欢使用它们的挑战。

无论如何,逻辑是有缺陷的,因为,这就是我的情况,如果开始偏移量是0x3D8A,结束偏移量是0x671D,两者之间的差异是0x2993。四舍五入是0x3000,也就是三个街区。该段实际上占用4个,分别是0x3000、0x4000、0x5000和0x6000。因此,我的下一个任务,不幸的是,我的最后一个任务,是找到该段所在的第一个块的偏移量与该段未所在的第一个块的偏移量之间的差值。

使用0x3D8A和0x671D,这将我带到了(0x7000 - 0x3000) >> 0xC,它成功地产生了正确数量的块,4。我写的方式是我想改进的,这是:

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

我知道我把一个简单的问题弄得太复杂了,但是我不知道如何把它写得更好。

那太尴尬了。我不知道我是怎么做到的而不是
(((OffsetEnd + 0xFFF) >> 12) - (OffsetStart >> 12));

看起来还是不完整。

编辑2:对不起,忘了说结束偏移量是排他的,不是包含的,是段的最后一个字节之后的位置,含义:

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

编辑3:根据Kerek的回答,我最后说:

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

. .或者,从0开始计数,

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

编辑4:忘记从0开始计数,我坚持使用:

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

这个按位表达式有更好的逻辑

假设您的数据范围为[start, end),则非常简单:

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指出的那样,您需要一个条件来区分最后一个("one-past")块是否为空,并在后一种情况下将块计数增加1。

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

这将有一个简洁的开始,它将看到startinggoffset是否落在块边界上。