有没有非常快的方法来查找整数的二进制对数?例如,给定一个数字 x = 52656145834278593348959013841835216159447547700274555627155488768这样的算法必须找到y = log(x,2),即215. x总是2的幂。
问题似乎很简单。所需要的只是找到最重要的1位的位置。有一个众所周知的方法FloorLog,但它不是很快,特别是对于很长的多字整数。
最快的方法是什么?
答案 0 :(得分:23)
Bit Twiddling Hacks您要找的是什么?
答案 1 :(得分:7)
快速破解:大多数浮点数表示会自动规范化值,这意味着它们可以在硬件中有效地执行循环Christoffer Hammarström mentioned。因此,如果数字在FP表示的指数范围内,那么只需将整数转换为FP并提取指数即可。 (在您的情况下,您的整数输入需要多个机器字,因此需要在转换中执行多个“移位”。)
答案 2 :(得分:4)
如果整数存储在uint32_t a[]
中,那么我的明显解决方案如下:
在a[]
上运行线性搜索,以在uint32_t
中找到具有最高值的非零a[i]
值a[]
(使用uint64_t
进行测试对于该搜索,如果您的计算机具有本机uint64_t
支持
应用bit twiddling hacks查找您在步骤1中找到的b
值uint32_t
的二进制日志a[i]
。
评估32*i+b
。
答案 3 :(得分:2)
答案是实现或语言相关。任何实现都可以存储有效位的数量以及数据,因为它通常是有用的。如果必须计算,则找到最重要的单词/肢体和该单词中最重要的位。
答案 4 :(得分:0)
通过使用二进制搜索,我头脑中的最佳选择是O(log(logn))方法。以下是64位(<= 2^63 - 1
)数字(在C ++中)的示例:
int log2(int64_t num) {
int res = 0, pw = 0;
for(int i = 32; i > 0; i --) {
res += i;
if(((1LL << res) - 1) & num)
res -= i;
}
return res;
}
这个算法基本上会给我提供最高数量的资源,例如(2^res - 1 & num) == 0
。当然,对于任何数字,你都可以在类似的事情中解决这个问题:
int log2_better(int64_t num) {
var res = 0;
for(i = 32; i > 0; i >>= 1) {
if( (1LL << (res + i)) <= num )
res += i;
}
return res;
}
请注意,此方法依赖于“bitshift”操作或多或少为O(1)的事实。如果不是这种情况,则必须预先计算2的所有幂,或者2^2^i
形式的数字(2 ^ 1,2 ^ 2,2 ^ 4,2 ^ 8等)和做一些乘法(在这种情况下不是O(1))。
答案 5 :(得分:0)
您可以事先创建一个对数数组。这将找到最多log(N)的对数值:
#define N 100000
int naj[N];
naj[2] = 1;
for ( int i = 3; i <= N; i++ )
{
naj[i] = naj[i-1];
if ( (1 << (naj[i]+1)) <= i )
naj[i]++;
}
数组naj是您的对数值。其中naj [k] = log(k)。 日志基于两个。
答案 6 :(得分:0)
这使用二进制搜索来找到最接近2的幂。
public static int binLog(int x,boolean shouldRoundResult){
// assuming 32-bit integer
int lo=0;
int hi=31;
int rangeDelta=hi-lo;
int expGuess=0;
int guess;
while(rangeDelta>1){
expGuess=(lo+hi)/2; // or (loGuess+hiGuess)>>1
guess=1<<expGuess;
if(guess<x){
lo=expGuess;
} else if(guess>x){
hi=expGuess;
} else {
lo=hi=expGuess;
}
rangeDelta=hi-lo;
}
if(shouldRoundResult && hi>lo){
int loGuess=1<<lo;
int hiGuess=1<<hi;
int loDelta=Math.abs(x-loGuess);
int hiDelta=Math.abs(hiGuess-x);
if(loDelta<hiDelta)
expGuess=lo;
else
expGuess=hi;
} else {
expGuess=lo;
}
int result=expGuess;
return result;
}