ROUND_UP
宏是依靠整数除法完成工作。它只会在两个参数都是整数时才起作用。我假设N
是要四舍五入的数字,而S
是应该四舍五入的时间间隔。也就是说,ROUND_UP(12, 5)
应该返回15,因为15是第一个间隔5比12大。
想象一下,我们正在向下舍入而不是向上。在这种情况下,宏将仅仅是:
#define ROUND_DOWN(N,S) ((N/S) * S)
ROUND_DOWN(12,5)
将返回10,因为(12/5)
在整数除法是2和2 * 5为10.但我们没有做ROUND_DOWN,我们正在做ROUND_UP 。因此,在我们进行整数除法之前,我们希望尽可能地增加精度。如果我们加入S
,它几乎可以在任何情况下工作; (((11 + 5)/ 5)* 5),并且由于整数除法中的16/5为3,所以我们得到15个。指定的倍数。 ROUND_UP(10, 5)
将返回15,这是错误的。所以不是添加S,而是添加S-1。这保证我们永远不会不必要地推动下一个“桶”。
PAGE_
宏与二进制数学有关。为了简单起见,我们假装我们正在处理8位值。我们假设PAGE_SIZE
是0b00100000
。 PAGE_SIZE-1
因此是0b00011111
。 ~(PAGE_SIZE-1)
然后是0b11100000
。
一个二进制&
将排队两个二进制数字,并留下一个1,两个数字都有1。因此,如果x
是0b01100111,操作会是这样的:
0b01100111 (x)
& 0b11100000 (~(PAGE_SIZE-1))
------------
0b01100000
你会注意到,该操作真的只有归零出最后5位。就这样。但那正是那个操作需要围绕到最近的间隔PAGE_SIZE
。请注意,这仅仅是因为PAGE_SIZE
恰恰是2的幂。这有点像说任何十进制数字,你可以通过清零最后两位数来舍入到最接近的100。它的工作原理非常简单,而且非常容易,但是如果您想要将其舍入到最接近的76的倍数,则完全不起作用。
PAGE_ROUND_UP
做同样的事情,但它会尽可能地增加切断它之前的页面。这有点像我可以通过将99添加到任意数字和然后将最后两位数字清零来四舍五入到最接近的100的倍数。 (我们添加PAGE_SIZE-1
的原因与我们上面添加的S-1
相同。)
祝您的虚拟内存好运!