我正在开发一个程序来处理使用散列的文件。数据被分成长度为 0x1000 的 block 。我需要计算具有特定起始和结束偏移覆盖的段的 block 数量。
例如,如果段的起始偏移量为 0x2000,结束位置为 0x3523,则表示它占用了两个 block ,0x2000 和 0x3000。它不占用数据 block 中的完整 0x2000 字节,但当它在其中时被认为是“占用一个 block ”。我的第一个想法是:
( ( EndingOffset - StartingOffset ) + 0xFFF ) >> 0xC
这相当于 Math.Ceil((EndingOffset - StartingOffset)/0x1000)
,但我是按位运算符的新手,喜欢使用它们的挑战。
无论如何,逻辑是有缺陷的,因为,这就是我遇到的情况,如果起始偏移量是 0x3D8A,结束偏移量是 0x671D,则两者之间的差值是 0x2993。四舍五入为 0x3000,或三个 block 。该段实际上占用了四个,0x3000、0x4000、0x5000和0x6000。所以我的下一列火车,不幸的是我的最后一列火车,是找到该段所在的第一个 block 的偏移量与该段不在的第一个 block 的偏移量之间的差异。
对于 0x3D8A 和 0x671D,这将我带到 (0x7000 - 0x3000) >> 0xC
,它成功地产生了正确数量的 block ,4。我写它的方式是我想要改进的,即:
BlockSize = ((((OffsetEnd + 0xFFF) >> 12) + 1) - ((OffsetStart + 0xFFF) >> 12));
我知道我已经把一个简单的问题复杂化了,但是我的小脑袋想不出如何把它写得更好。
编辑:这很尴尬。我不知道我是怎么想到的而不是
(((OffsetEnd + 0xFFF) >> 12) - (OffsetStart >> 12));
虽然看起来还不完整。
edit 2:抱歉,忘了说结束偏移量是独占的,不包含在内,是段最后一个字节之后的位置,意思是:
(((OffsetEnd - 1 + 0xFFF) >> 12) - (OffsetStart >> 12));
编辑 3:根据 Kerek 的回答,我最终得到:
BlockSize = 1 + (offsetEnd - 1 >> 12) - (offsetStart >> 12);
..或者,从 0 开始计数,
BlockSize = (offsetEnd - 1 >> 12) - (offsetStart >> 12);
编辑 4:忘记从零开始计数,我坚持:
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
的 bitfiddling 等价物是 >> 12
。
您的数据将占据 block 范围 [start_block, end_block)。请注意, block 0 是 [0x0000, 0x1000), block 1 是 [0x1000, 0x2000)`,等等
正如@Ron 指出的那样,您需要一个条件来区分最后一个(“one-past”) block 是否为空,并在后一种情况下将 block 计数递增 1。
关于c# - 这个按位表达式有更好的逻辑吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8721963/