Быстрая ближайшая мощность 2 в JavaScript?
Есть ли более быстрая альтернатива следующему выражению:
Math.pow(2,Math.floor(Math.log(x)/Math.log(2)))
То есть, взяв самую близкую (меньшую) целую степень 2 двойника? У меня такое выражение во внутреннем цикле. Я подозреваю, что это может быть намного быстрее, учитывая, что можно просто взять мантиссу из представления IEEE 754 двойника.
Ответы
Ответ 1
Использование ES6 Math.clz32 (n) для подсчета ведущих нулей 32-разрядного целого числа:
// Compute nearest lower power of 2 for n in [1, 2**31-1]:
function nearestPowerOf2(n) {
return 1 << 31 - Math.clz32(n);
}
// Examples:
console.log(nearestPowerOf2(9)); // 8
console.log(nearestPowerOf2(33)); // 32
Ответ 2
Здесь другая альтернатива, с ориентирами. Хотя оба они кажутся сопоставимыми, мне нравится, когда я могу пол или потолок.
function pow2floor(v) {
var p = 1;
while (v >>= 1) {
p <<= 1;
}
return p;
}
function pow2ceil(v) {
var p = 2;
while (v >>= 1) {
p <<= 1;
}
return p;
}
function MATHpow2(v) {
return Math.pow(2, Math.floor(Math.log(v) / Math.log(2)))
}
function runner(fn, val) {
var res;
for (var i = 0; i < 10000000; i++) {
fn(val);
}
return
}
var then;
var source = 3000;
then = new Date().getTime();
var a = runner(pow2floor, source);
console.log(" a result: " + pow2floor(source));
console.log(" pow2floor: " + (new Date().getTime() - then));
then = new Date().getTime();
var b = runner(MATHpow2, source);
console.log(" b result: " + MATHpow2(source));
console.log(" MATHpow2: " + (new Date().getTime() - then));
// my results (results vary by system and browser)
// pow2floor: 217 (ms) winner!
// MATHpow2: 2773 (ms) loser
Ответ 3
К сожалению, вам понадобится эквивалент функции C frexp
. Лучшее, что я смог найти, находится в JSFiddle, а в его коде используется Math.pow
.
Есть несколько альтернатив, которые вы могли бы сравнить, используя реальные данные, вместе с вашей текущей попыткой:
- Начиная с 1.0, умножайте его на 2.0 до тех пор, пока оно больше или равно входу, а затем умножьте его на 0,5, пока оно не станет меньше или равно входу. Вам понадобится специальная обработка значений на концах двойного диапазона.
- Сохраняйте массив возрастающих значений всех точных степеней двух в двойном диапазоне и выполняйте двоичный поиск.
Первый, скорее всего, будет самым быстрым, если ваши данные, как правило, близки к 1.0. Второй требует до 11 условных ветвей.