Как работает округление числа вверх до кратного?
Вычитал в одной статье технику, которая позволяет округлить число X в большую сторону так, чтобы оно было кратно Y.
int roundup(int x, int y) {
return ((x+y-1) & ~(y-1));
}
int main() {
int x = 1020; // number to round up
x = roundup(x, 512);
return 0;
}
Этот пример кода округляет X до 1024, однако нигде не объясняется что происходит в функции roundup, поэтому прошу у вас объяснения по этому вопросу.
Ответы (2 шт):
Это работает при округлении до степеней двойки, а не до любого числа. Впрочем, такое округление нужно часто.
(x+y-1)
увеличивает число x так, чтобы получилось число, не меньше кратного y (включая x!), но не достигающее следующего кратного. Например, при y=4
8 + 3 = 11 8<=11<12
9 + 3 = 12 12<=12<16
10 + 3 = 13 12<=13<16
11 + 3 = 14 12<=14<16
12 + 3 = 15 12<=15<16
13 + 3 = 16 16<=16<20
Инверсия
~(y-1)
при этой операции над числом y=2^k в скобках получается бинарное число с хвостом из единиц, причем количество этих единиц соответствует степени двойки k
4-1 = 3 = 0b00000011
А при его инверсии получается число из единиц с хвостом из k нулей.
~0b00000011 = 0b11111100
При выполнении операции AND обнуляется k последних бит, вот и получается кратность y
14 = 0b00001110
0b00001110 & 0b11111100 = 0b00001100 = 12
Про более универсальный вариант с целочисленным делением-умножением Harry уже написал
Секрет в &~(y-1), который обнуляет биты в конце, т.е. по сути выполняет деление на y с последующим умножением на него же и обеспечивает результат, кратный y.
int roundup(int x, int y) {
return ((x+y-1)/y*y);
}
Кстати, этот вариант будет работать и для других y, не только степеней двойки.