C:快速求幂(幂2)和#x2B;整数的二进制对数(向上舍入)

C:快速求幂(幂2)和#x2B;整数的二进制对数(向上舍入),c,math,casting,bit-manipulation,C,Math,Casting,Bit Manipulation,我试图找到用C计算以下内容的最快方法: p = 2^(ceil(log2(x))); 到目前为止,看看堆栈溢出(和其他地方)中的答案,我已经得出了以下结论: #define LOG2(X) ((int) (8*sizeof (unsigned long long) - __builtin_clzll((X)) - 1)) int p = 1 << LOG2( (unsigned long long)x ); #定义LOG2(X)((int)(8*sizeof(unsigned l

我试图找到用C计算以下内容的最快方法:

p = 2^(ceil(log2(x)));
到目前为止,看看堆栈溢出(和其他地方)中的答案,我已经得出了以下结论:

#define LOG2(X) ((int) (8*sizeof (unsigned long long) - __builtin_clzll((X)) - 1))
int p = 1 << LOG2( (unsigned long long)x );
#定义LOG2(X)((int)(8*sizeof(unsigned long-long)-(X))-1))

int p=1见鬼,我来回答这个问题

要将“向下舍入”转换为“向上舍入”,只需计算向下舍入的日志(x-1)并将1添加到结果中

通常,向上舍入的结果总是比向下舍入的结果多1(即地板(某物)和天花板(某物)相差1),除非某物是一个精确的整数;在这种情况下,当您的输入是2的幂时。从输入中减去1,然后在结果中加1的技巧是普遍的;它适用于任何单调函数,如log()


为了完全正确,您可能希望将特例0作为输入,但对于原始公式也是如此,因为log(0)未定义。

见鬼,我会回答这个问题

要将“向下舍入”转换为“向上舍入”,只需计算向下舍入的日志(x-1)并将1添加到结果中

通常,向上舍入的结果总是比向下舍入的结果多1(即地板(某物)和天花板(某物)相差1),除非某物是一个精确的整数;在这种情况下,当您的输入是2的幂时。从输入中减去1,然后在结果中加1的技巧是普遍的;它适用于任何单调函数,如log()


为了完全正确,您可能希望将特例0作为输入,但对于原始公式也是如此,因为log(0)未定义。

我非常确定:

2^(ceil(log2(x)))
可以读取为大于或等于
x
的两个值的最小幂,但
x
为零的值未定义除外

在这种情况下,可以通过以下方式找到:

unsigned int fn (unsigned int x) {
    if (x == 0) return 0;
    unsigned int result = 1;
    while ((result < x) && (result != 0))
        result <<= 1;
    return result;
}

我非常肯定:

2^(ceil(log2(x)))
可以读取为大于或等于
x
的两个值的最小幂,但
x
为零的值未定义除外

在这种情况下,可以通过以下方式找到:

unsigned int fn (unsigned int x) {
    if (x == 0) return 0;
    unsigned int result = 1;
    while ((result < x) && (result != 0))
        result <<= 1;
    return result;
}

谢谢你的快速回答。我本来可以自己想出来的(掌心)。顺便问一下,我的解决方案还有什么问题吗?任何可预见的可移植性问题?
内置clzll
是一个GCC扩展。几乎可以肯定的是,Clang和英特尔C编译器支持它,但我不了解微软。此外,最终结果可以大于
int
。在任何情况下,当输入大于2^63时,它都可能溢出。。。基本上,我建议仔细考虑边界情况(x=0,x非常大)。确保“计算日志(x-1)向下取整并添加1”适用于2的精确幂,如1,2,4?@chux:对于2,4,8,…,是的,我确信它适用。对于x=1,我认为它会失败,因为0未定义
\uuuuu builtin\uclzll
(请参阅)。因此,对于这个解决方案,需要使用特例x=1。它应该仍然比循环快得多,至少在x86上是这样,因为clz(又名.bsr)是一条单指令。感谢您的快速回答。我本来可以自己想出来的(掌心)。顺便问一下,我的解决方案还有什么问题吗?任何可预见的可移植性问题?
内置clzll
是一个GCC扩展。几乎可以肯定的是,Clang和英特尔C编译器支持它,但我不了解微软。此外,最终结果可以大于
int
。在任何情况下,当输入大于2^63时,它都可能溢出。。。基本上,我建议仔细考虑边界情况(x=0,x非常大)。确保“计算日志(x-1)向下取整并添加1”适用于2的精确幂,如1,2,4?@chux:对于2,4,8,…,是的,我确信它适用。对于x=1,我认为它会失败,因为0未定义
\uuuuu builtin\uclzll
(请参阅)。因此,对于这个解决方案,需要使用特例x=1。它应该仍然比循环快得多,至少在x86上是这样,因为clz(又名.bsr)是一条单指令。如果该
x
是一个
int
x
是一个带整数值的FP?@chux澄清了它。它将始终是int类型。顺便说一句,如果您重视可移植性,我认为您可能应该使用
CHAR\u BIT
,而不是
8
,尽管使用内在函数可能会使这一点变得不那么重要:-)请在您的条件下明确“x将始终是一个整数”。如果该
x
是一个
int
x
是一个带整数值的FP?@chux澄清了它。它将始终是int类型。顺便说一下,如果您重视可移植性,我认为您可能应该使用
CHAR\u BIT
而不是
8
,尽管使用内在函数可能会使其不那么重要:-)关于“2^(cel(log2(x))”代表的内容,您是对的。你是正确的解决方案(显然)。我不确定它是否会比我所拥有的更快(我可能会在以后运行这两个程序来找出答案)。不管怎么说,这仍然是一个非常简洁直观的解决方案(对它竖起大拇指)。Thanks@Haider,它可能不会比您已经为具有
\uuuu内置
内在特性的平台提供的解决方案快,但它可能会更好地适用于那些没有这样做的平台:-)关于“2^(ceil(log2(x))”代表的内容,您是对的。你是正确的解决方案(显然)。我不确定它是否会比我所拥有的更快(我可能会在以后运行这两个程序来找出答案)。不管怎么说,这仍然是一个非常简洁直观的解决方案(对它竖起大拇指)。Thanks@Haider,它可能不会比您已经为具有
\uuuuu内置
内在特性的平台提供的解决方案快,但它可能会更好地适用于那些不具有
内在特性的平台:-)