La macro ROUND_UP
si basa sulla divisione integer per eseguire il lavoro. Funzionerà solo se entrambi i parametri sono interi. Suppongo che N
sia il numero da arrotondare e S
è l'intervallo su cui deve essere arrotondato. Cioè, ROUND_UP(12, 5)
dovrebbe restituire 15, poiché 15 è il primo intervallo di 5 maggiore di 12.
Immagina di arrotondare il volume anziché salire. In tal caso, la macro sarebbe semplicemente:
#define ROUND_DOWN(N,S) ((N/S) * S)
ROUND_DOWN(12,5)
sarebbe ritorno 10, a causa (12/5)
nella divisione intera è 2, e 2 * 5 è 10. Ma non stiamo facendo ROUND_DOWN, stiamo facendo ROUND_UP . Quindi, prima di fare la divisione intera, vogliamo aggiungere il più possibile senza perdere la precisione. Se aggiungessimo S
, funzionerebbe in quasi tutti i casi; ROUND_UP(11,5)
diventerebbe (((11 + 5)/5) * 5), e dal 16/5 nella divisione intera è 3, otterremmo 15.
Il problema si presenta quando passiamo un numero che è già arrotondato a il multiplo specificato. ROUND_UP(10, 5)
restituire 15, e questo è sbagliato. Quindi, invece di aggiungere S, aggiungiamo S-1. Questo garantisce che non spingeremo mai qualcosa fino al prossimo "secchio" inutilmente.
I macro PAGE_
hanno a che fare con la matematica binaria. Faremo finta di avere a che fare con valori a 8 bit per motivi di semplicità. Supponiamo che PAGE_SIZE
sia 0b00100000
. PAGE_SIZE-1
è quindi 0b00011111
. ~(PAGE_SIZE-1)
è quindi 0b11100000
.
Un binario &
allineerà due numeri binari e lascerà un 1 ovunque che entrambi i numeri abbiano un 1.Così, se x
era 0b01100111, l'operazione sarebbe andata in questo modo:
0b01100111 (x)
& 0b11100000 (~(PAGE_SIZE-1))
------------
0b01100000
Noterete che l'operazione in realtà solo azzerato-out gli ultimi 5 bit. È tutto. Ma quella era esattamente l'operazione necessaria per arrotondare al più vicino intervallo di PAGE_SIZE
. Si noti che questo ha funzionato solo perché PAGE_SIZE
era esattamente una potenza di 2. È un po 'come dire che per qualsiasi numero decimale arbitrario, è possibile arrotondare al 100 più vicino semplicemente azzerando le ultime due cifre. Funziona perfettamente, ed è veramente facile da fare, ma non funzionerebbe affatto se si cercasse di arrotondare al multiplo più vicino di 76.
PAGE_ROUND_UP
fa la stessa cosa, ma aggiunge il più possibile la pagina prima di tagliarla. È un po 'come posso arrotondare al multiplo più vicino a 100 aggiungendo 99 a qualsiasi numero e quindi a azzerando le ultime due cifre. (Aggiungiamo PAGE_SIZE-1
per la stessa ragione per cui abbiamo aggiunto S-1
sopra.)
Buona fortuna con la tua memoria virtuale!