一个有趣的问题。不取决于大小是什么意思
int 或字节中的位数?遇到不同的号码
一个字节中的位数,你将不得不使用不同的机器,
一组不同的机器指令,可能会或可能不会影响
回答。
无论如何,有点模糊地基于 Mihran 提出的第一个解决方案,
我明白了:
int
topBit( unsigned x )
{
int r = 1;
if ( x > 1 ) {
if ( frexp( static_cast<double>( x ), &r ) != 0.5 ) {
++ r;
}
}
return r - 1;
}
这在输入值必须准确的约束内有效
可以用double 表示;如果输入是unsigned long long,这个
可能不是这样,在一些更奇特的平台上,它
unsigned 甚至可能不是这样。
我唯一能做到的其他恒定时间(相对于位数)
想到的是:
int
topBit( unsigned x )
{
return x == 0 ? 0.0 : ceil( log2( static_cast<double>( x ) ) );
}
,它对于 x 具有相同的约束
可以用double 表示,也可能会出现舍入错误
浮点运算中固有的(尽管如果 log2 是
正确实施,我认为不应该是这种情况)。如果
您的编译器不支持log2(C++11 功能,但也存在
在 C90 中,所以我希望大多数编译器已经实现
它),那么当然可以使用log( x ) / log( 2 ),但我怀疑
这将增加舍入误差的风险,从而导致
结果错误。
FWIW,我发现位数的 O(1) 有点不合逻辑,因为
我在上面指定的原因:位数只是众多之一
“恒定因素”取决于您运行的机器。
无论如何,我想出了以下纯整数解决方案,即
位数为 O(lg 1),其他一切为 O(1):
template< int k >
struct TopBitImpl
{
static int const k2 = k / 2;
static unsigned const m = ~0U << k2;
int operator()( unsigned x ) const
{
unsigned r = ((x & m) != 0) ? k2 : 0;
return r + TopBitImpl<k2>()(r == 0 ? x : x >> k2);
}
};
template<>
struct TopBitImpl<1>
{
int operator()( unsigned x ) const
{
return 0;
}
};
int
topBit( unsigned x )
{
return TopBitImpl<std::numeric_limits<unsigned>::digits>()(x)
+ (((x & (x - 1)) != 0) ? 1 : 0);
}
一个好的编译器应该能够内联递归调用,结果是
接近最优代码。