Это улучшение первого ответа, которое не зависит от реализации IEEE, хотя я полагаю, что это быстро только на машинах IEEE, где frexp()
является в основном бесплатной функцией.
Вместо отбрасывания дроби, возвращаемой frexp
, можно использовать ее для линейной интерполяции. Значение дроби составляет от 0,5 до 1,0, если оно положительное, поэтому мы растягиваем значение от 0,0 до 1,0 и добавляем его к показателю степени.
На практике, похоже, что эта быстрая оценка хороша примерно до 5-10%, всегда возвращая значение, которое является немного низким. Я уверен, что это можно сделать лучше, настроив коэффициент масштабирования 2*
.
#include <cmath>
double log2_fast(double d) {
int exponent;
double fraction = std::frexp(d, &exponent);
return (result-1) + 2* (fraction - 0.5);
}
Вы можете убедиться, что это разумное быстрое приближение, с помощью:
#include <cmath>
int main()
{
for(double x=0.001;x<1000;x+=0.1)
{
std::cout << x << " " << std::log2(x) << " " << log2_fast(x) << "\n";
}
}