Вычисление двоичного логарифма
Найти ответ на вопрос, как в стандартной библиотеке реализовано вычисление логарифма, оказалось сложнее, чем можно подумать. Во-первых, алгоритмов вычисления довольно много: от наивной итерации по Тейлору до хитрых методов с таблицами. Во-вторых, реализация будет отличаться в зависимости от архитектуры процессора, наличия векторизации (SIMD, SVE и прочие страшные аббревиатуры) и от авторов библиотеки (GNU, musl, UCRT и т.п.).
Если смотреть на среднебольничную реализацию, то это будут математические преобразования по сужению области определения, набор предвычисленных таблиц и вычисление 5-7 членов ряда Тейлора. Некоторые процессоры имеют встроенную команду fyl2x
для x * log2(y)
, и она даже используется, правда она может выполнятся довольно медленно: на некоторых старых процессорах — больше 1000 тактов, а в среднем за 50-100 тактов.
При этом двоичный логарифм довольно особенный. Если работать с числами с плавающей точкой и нам не очень важна дробная часть, то можно просто взять показатель двоичной степени при помощи frexpf
. А если работаем с целыми числами, то достаточно знать позицию первой единицы слева или количество нулей слева — для этого у некоторых процессора есть команды bsr
и/или clz
соответственно, а в GCC — встроенная функция __builtin_clz
.