Reputation: 4191
I have a memory region, which is divided in blocks of predefined BLOCKSIZE
size. Given a memory chunk, defined by its offset OFFSET
in bytes and SIZE
in bytes, how to efficiently calculate a number of blocks, containing this memory chunk?
For example, let's say the BLOCKSIZE=8
. Then a memory chunk with OFFSET=0
and SIZE=16
will take 2 blocks, but a chunk with OFFSET=4
and SIZE=16
will take 3 blocks.
I can write a formula like this (using integer arithmetics in C):
numberOfBlocks = (OFFSET + SIZE - 1) / BLOCKSIZE - (OFFSET / BLOCKSIZE) + 1;
This calculation will take 2 divisions and 4 additions. Can we do better, provided that the BLOCKSIZE
is a power of 2 and OFFSET >= 0
and SIZE > 0
?
UPDATE: I uderstand that division can be replaced by shifting in this case.
Upvotes: 0
Views: 2441
Reputation: 180430
Can we do better, provided that the
BLOCKSIZE
is a power of 2?
I don't think so. Your (corrected) formula is basically (index of the first block after the chunk) - (index of the first containing any part of the chunk). You could formulate it differently -- say, as the sum of a base number of blocks plus an adjustment for certain layouts that require one extra block -- but that actually increases the number of operations needed by a couple:
numberOfBlocks = (SIZE + BLOCKSIZE - 1) / BLOCKSIZE
+ ((SIZE % BLOCKSIZE) + (OFFSET % BLOCKSIZE)) / BLOCKSIZE;
I don't see any way around performing (at least) two integer divisions (or equivalent bit shifts), because any approach to the calculation requires computing two block counts. These two computations cannot be combined, because each one requires a separate remainder truncation.
That BLOCKSIZE
is a power of two may help you choose more efficient operations, but it does not help reduce the number of operations required. However, you could reduce the number of operations slightly if you could rely on SIZE
to be a multiple of BLOCKSIZE
. In that case, you could do this:
numberOfBlocks = SIZE / BLOCKSIZE + (OFFSET % BLOCKSIZE) ? 1 : 0;
Alternatively, if it would be sufficient to compute an upper bound on the number of blocks covered, then you could do this:
numberOfBlocksBound = SIZE / BLOCKSIZE + 2;
or slightly tighter in many cases, but more costly to compute:
numberOfBlocksBound = (SIZE + BLOCKSIZE - 1) / BLOCKSIZE + 1;
Upvotes: 2