В очередной раз, читая исходники HashMap'ы я обнаружил прикольный алгоритм для вычисления ближайшей степени двойки некоторого числа:
// вынес в отдельную функциюАлгоритм работает только в большую сторону, то есть для числа 5 ближайшей степенью двойки будет число 8, а не 4.
fun pow2(number: Int): Int {
val newNumber = -1 ushr (number - 1)
.countLeadingZeroBits()
if (newNumber < 0) return 1
return newNumber + 1
}
Разберёмся как работает код, чтобы не усложнять всем жизнь я буду оперировать 1-байтовым числом, для Int и Long логика абсолютна такая же:
11111111 // число -1
00000101 // число 5
00001000 // число 8
// вычитаем единицу из текущего числа, это нужно для случаев, когда число уже является степенью двойки
00000101 - 1 = 00000100
// countLeadingZeroBits() под капотом вызывает статический метод Integer.numberOfLeadingZeros(), который возвращает количество нулей перед старшим битом числа
00000100 // 5 нулей до старшего бита
// ushr безнаковый сдвиг битов вправо, безнаковый означает что при сдвиге старшая часть будет заполняться нулями, а не повторять младшие биты
11111111 ushr 5 = 00000111
// прибавляем единичку
00000111 + 1 = 00001000
// получили результат 8
00001000
Как вам такая битовая магия?) Лично мне по душе такие штуки: со стороны они кажутся сложными и запутанными, но после парочки примеров возникает своеобразный wow-эффект.
P.S. Если есть желание копать дальше, чекайте Integer класс, там полно статических методов с битовой арифметикой.
Пишите в комментах ваше мнение и всем хорошего кода!
