Я работаю на платформе с фиксированной запятой (арифметика с плавающей запятой не поддерживается).
Я представляю любое рациональное число q
как минимальное значение q * (1 << precision)
.
Мне нужен эффективный метод для вычисления базы журнала 2 из x
, где 1 < x < 2
.
Вот что я сделал до сих пор:
uint64_t Log2(uint64_t x, uint8_t precision)
{
uint64 res = 0;
uint64 one = (uint64_t)1 << precision;
uint64 two = (uint64_t)2 << precision;
for (uint8_t i = precision; i > 0 ; i--)
{
x = (x * x) / one; // now 1 < x < 4
if (x >= two)
{
x >>= 1; // now 1 < x < 2
res += (uint64_t)1 << (i - 1);
}
}
return res;
}
Это работает хорошо, однако это сказывается на общей производительности моей программы, что требует выполнения этого для большого количества входных значений.
Как бы то ни было, используемое precision
равно 31, но это может измениться, поэтому мне нужно сохранить его как переменную.
Есть ли какие-либо оптимизации, которые я могу применить здесь?
Я думал о чем-то вроде "сначала умножь, потом суммируй".
Но это подразумевало бы вычисление x ^ (2 ^ precision)
, которое очень быстро переполнилось бы.
Спасибо.
ОБНОВЛЕНИЕ:
Раньше я пытался избавиться от ветки, но это только ухудшило ситуацию:
for (uint8_t i = precision; i > 0 ; i--)
{
x = (x * x) / one; // now 1 < x < 4
uint64_t n = x / two;
x >>= n; // now 1 < x < 2
res += n << (i - 1);
}
return res;
one
? Развеx = (x * x) >> precision
не эквивалентно? - person rodrigo   schedule 04.08.2017x
находится между 1 и 2, то представлениеx
с фиксированной точкой имеет 33 бита. Выполнение(x * x)
приведет к переполнению 66 битов типаuint64_t
. - person rodrigo   schedule 04.08.2017uint256_t
, но я не хотел упоминать об этом здесь (и начать получать несвязанные вопросы о платформе). Так что не стесняйтесь пересматриватьprecision=31
, и я исправлю это в вопросе. Спасибо. - person goodvibration   schedule 04.08.2017