Для вычислений на глазном яблоке логарифм по основанию 2 близок к логарифму по основанию 10 плюс натуральный логарифм. Очевидно, что лучше написать более точную (и более быструю) версию программы.
Дэвид Торнли
Для целых чисел вы можете выполнить цикл с правым битовым смещением и останавливаться при достижении 0. Счетчик циклов является приближением журнала
Для этого также есть хороший метод бит-тидлинга (взятый из Integer.highestOneBit(int)метода Java ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
Joey
38
... илиwhile (i >>= 1) { ++l; }
Ли Дэниел Крокер
2
@Joey Это будет работать, если целое число имеет ширину 32 бита, не так ли? Для 64-битной версии было бы доп i>>32. Но поскольку в Java есть только 32-битные целые числа, это нормально. Для C / C ++ это необходимо учитывать.
Обратите внимание, что вы можете предварительно вычислить log10 (2) для повышения производительности.
corsiKa
@Johannes: Я сомневаюсь, что компилятор предварительно вычислит log10 (2). Компилятор не знает, что log10 будет каждый раз возвращать одно и то же значение. Насколько известно компилятору, log10 (2) может возвращать разные значения при последовательных вызовах.
abelenky
@abelenky: Хорошо, я беру это обратно. Поскольку компилятор никогда не видит источник log()реализации, он этого не сделает. Виноват.
Joey
3
@abelenky: Поскольку log10()это функция, определенная в стандарте C, компилятор может обработать ее «специально», включая предварительное вычисление результата, что, как я считаю, было предложением @Johannes?
caf
1
@CarlNorum: я только что проверил, и gcc 4.7 по крайней мере заменяет log10(2)константу.
caf
8
Если вы хотите сделать это быстро, вы можете использовать таблицу поиска, как в Bit Twiddling Hacks (только целочисленный log2).
uint32_t v;// find the log base 2 of 32-bit vint r;// result goes herestaticconstintMultiplyDeBruijnBitPosition[32]={0,9,1,10,13,21,2,29,11,14,16,18,22,25,3,30,8,12,20,28,15,17,24,7,19,27,23,6,26,5,4,31};
v |= v >>1;// first round down to one less than a power of 2
v |= v >>2;
v |= v >>4;
v |= v >>8;
v |= v >>16;
r =MultiplyDeBruijnBitPosition[(uint32_t)(v *0x07C4ACDDU)>>27];
Кроме того, вам следует взглянуть на встроенные методы вашего компилятора, например, _BitScanReverseкоторые могут быть быстрее, потому что они могут полностью вычисляться аппаратно.
Почему умножение и поиск по таблице в конце? Не могли бы вы просто сделать (v + 1), которое округлило бы до следующей степени двойки? А затем вы можете перейти вправо на одну, чтобы округлить до следующей степени 2.
Сафайет Ахмед,
@SafayetAhmed Пожалуйста, опишите, как вы хотите найти log2 числа с помощью этого метода. Я не знаю более простого способа получить эту ценность. Помимо использования приведенной выше арифметики с поисковой таблицей, можно использовать итеративный / рекурсивный алгоритм или использование специального / встроенного оборудования для выполнения вычислений.
bkausbk
Скажем, биты 32-битной переменной v пронумерованы от 0 (LSB) до N (MSB). Скажем, старший бит набора v равен n. Было бы правильно сказать, что n представляет пол (log2 (v))? Разве вам не интересно просто найти n с учетом v?
Сафайет Ахмед,
Я понял, что то, что я описал, даст вам ближайшую наименьшую степень двойки, а не фактический логарифм. Умножение и поиск в таблице предназначены для перехода от степени двойки к логарифму. Вы сдвигаете число 0x07C4ACDD влево на некоторую величину. Величина сдвига влево будет зависеть от степени двойки. Число таково, что любая последовательная последовательность из 5 бит уникальна. (0000 0111 1100 0100 0110 1100 1101 1101) дает вам последовательности (00000) (00001) ... (11101). В зависимости от того, насколько далеко вы сдвинетесь влево, вы получите один из этих 5-битных шаблонов. Затем поиск по таблице. Очень хорошо.
В этом решении есть несколько ошибок, но в целом это хорошо, если вы хотите избежать операций с плавающей запятой. Вы полагаетесь на переполнение, чтобы это сработало, поскольку вы инициализируете целое число без знака с -1. Это можно исправить, установив его на 0 и затем вернув значение - 1, если вы проверяете регистр 0, что вы и делаете. Другая проблема заключается в том, что вы полагаетесь на остановку цикла, когда n == 0, что вы должны указать явно. Кроме того, это замечательно, если вы хотите избежать плавающих точек.
Риан Куинн
2
Вы должны включить math.h (C) или cmath (C ++). Конечно, имейте в виду, что вы должны следовать математике, которую мы знаем ... только числа> 0.
Мне нужно было иметь большую точность, чем просто положение самого старшего бита, а в микроконтроллере, который я использовал, не было математической библиотеки. Я обнаружил, что простое использование линейного приближения между значениями 2 ^ n для аргументов с положительным целым числом работает хорошо. Вот код:
Все приведенные выше ответы верны. Этот мой ответ ниже может быть полезен, если кому-то это нужно. Я видел это требование во многих вопросах, которые мы решаем с помощью C.
log2 (x) = logy (x) / logy (2)
Однако, если вы используете язык C и хотите получить целочисленный результат, вы можете использовать следующее:
Проконсультируйтесь с вашим базовым курсом математики log n / log 2. Неважно, выберете вы logили, log10в этом случае, деление на logновую базу дает свое.
Ответы:
Простая математика:
журнал 2 ( x ) = журнал y ( x ) / журнал y (2)
где y может быть любым, что для стандартных функций журнала равно 10 или e .
источник
У C99 есть
log2
(какlog2f
иlog2l
для float и long double).источник
Если вы ищете интегральный результат, вы можете просто определить самый высокий бит, установленный в значении, и вернуть его позицию.
источник
Integer.highestOneBit(int)
метода Java ):i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); return i - (i >>> 1);
while (i >>= 1) { ++l; }
i>>32
. Но поскольку в Java есть только 32-битные целые числа, это нормально. Для C / C ++ это необходимо учитывать.(умножение может быть быстрее деления)
источник
источник
Как указано на http://en.wikipedia.org/wiki/Logarithm :
Которое значит что:
источник
log()
реализации, он этого не сделает. Виноват.log10()
это функция, определенная в стандарте C, компилятор может обработать ее «специально», включая предварительное вычисление результата, что, как я считаю, было предложением @Johannes?log10(2)
константу.Если вы хотите сделать это быстро, вы можете использовать таблицу поиска, как в Bit Twiddling Hacks (только целочисленный log2).
Кроме того, вам следует взглянуть на встроенные методы вашего компилятора, например,
_BitScanReverse
которые могут быть быстрее, потому что они могут полностью вычисляться аппаратно.Также обратите внимание на возможные дубликаты. Как сделать целое число log2 () в C ++?
источник
источник
В основном то же, что и у tomlogic .
источник
Вы должны включить math.h (C) или cmath (C ++). Конечно, имейте в виду, что вы должны следовать математике, которую мы знаем ... только числа> 0.
Пример:
источник
Мне нужно было иметь большую точность, чем просто положение самого старшего бита, а в микроконтроллере, который я использовал, не было математической библиотеки. Я обнаружил, что простое использование линейного приближения между значениями 2 ^ n для аргументов с положительным целым числом работает хорошо. Вот код:
В моей основной программе мне нужно было вычислить N * log2 (N) / 2 с целочисленным результатом:
temp = (((uint32_t) N) * приблизительно_log_base_2_N_times_256) / 512;
и все 16-битные значения никогда не отклонялись более чем на 2%
источник
Все приведенные выше ответы верны. Этот мой ответ ниже может быть полезен, если кому-то это нужно. Я видел это требование во многих вопросах, которые мы решаем с помощью C.
log2 (x) = logy (x) / logy (2)
Однако, если вы используете язык C и хотите получить целочисленный результат, вы можете использовать следующее:
Надеюсь это поможет.
источник
Проконсультируйтесь с вашим базовым курсом математики
log n / log 2
. Неважно, выберете выlog
или,log10
в этом случае, деление наlog
новую базу дает свое.источник
Улучшенная версия того, что сделал Устаман Сангат
источник