简体   繁体   English

C:整数的快速幂运算(幂2)+二进制对数(四舍五入)

[英]C : Fast Exponentiation (Power 2) + Binary Logarithm (Rounded up) for Integers

I am trying to find the fastest way to compute the following in C: 我试图找到最快的方法来计算C中的以下内容:

p = 2^(ceil(log2(x)));

So far, looking at answers in Stack overflow (and other places) I have got this far: 到目前为止,在堆栈溢出(以及其他地方)中查看答案,我已经了解到了这一点:

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

x will always be an integer (type int ) and greater than zero. x将始终是整数(类型为int )且大于零。 I got the LOG2 solution from this stackoverflow question . 我从这个stackoverflow 问题获得了LOG2解决方案。 There are several good answer but all of them seem to be rounding down (including this one). 有几个很好的答案,但似乎所有人都在四舍五入(包括这个)。 I need to round up. 我需要四舍五入。 I am not comfortable enough with the solutions to modify them to round up. 我对解决方案不满意,无法对其进行修改。 Any help would be appreciated !!!! 任何帮助,将不胜感激 !!!!

I'm pretty certain that: 我可以肯定的是:

2^(ceil(log2(x)))

can be read as the lowest power of two that's greater than or equal to x , other than where x is zero, where it's undefined. 可以被理解为大于或等于x的2的最低幂,但x为零(未定义)除外。

In which case, it can be found with something like: 在这种情况下,可以通过以下方式找到它:

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

which is relatively efficient, needing at most one iteration per number of bits in the data type (32 for a 32-bit integer, for example). 这是相对有效的,数据类型中的每个位数最多需要迭代一次(例如对于32位整数为32)。

This will return either the correct power of two, or zero on error (if the input number is zero, or the result is not able to be represented in the data type). 这将返回正确的2的幂或错误时为零(如果输入数字为零,或者结果无法用数据类型表示)。

You can see it in action in the following program: 您可以在以下程序中看到它的运行情况:

#include <stdio.h>
#include <limits.h>

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

int main (void) {
    printf ("%u -> %u\n\n", 0, fn(0));
    for (unsigned int i = 1; i < 20; i++)
        printf ("%u -> %u\n", i, fn(i));
    printf ("\n%u -> %u\n", UINT_MAX, fn(UINT_MAX));
    return 0;
}

which outputs: 输出:

0 -> 0

1 -> 1
2 -> 2
3 -> 4
4 -> 4
5 -> 8
6 -> 8
7 -> 8
8 -> 8
9 -> 16
10 -> 16
11 -> 16
12 -> 16
13 -> 16
14 -> 16
15 -> 16
16 -> 16
17 -> 32
18 -> 32
19 -> 32

4294967295 -> 0

What the heck, I'll make this an answer. 哎呀,我会回答这个问题。

To convert "round down" to "round up", just compute log(x-1) rounded down and add 1 to the result. 要将“四舍五入”转换为“四舍五入”,只需计算四舍五入的log(x-1)并将结果加1。

In general, the result of rounding something up is always 1 more than rounding down (ie floor(something) and ceil(something) differ by 1), except when the something is an exact integer; 通常,四舍五入的结果总是比四舍五入多1(即floor(某物)和ceil(某物)相差1),除非某物是一个精确整数。 in this case, when your input is a power of 2. The trick of subtracting 1 from the input and adding 1 to the result is general; 在这种情况下,当您的输入为2的幂时,从输入中减去1并在结果中加1的技巧很普遍; it will work for any monotonic function like log(). 它适用于任何单调函数,例如log()。

For complete correctness you might want to special case 0 as input, but that is true for your original formulation, too, since log(0) is undefined. 为了完全正确,您可能希望将特殊情况0作为输入,但是对于原始公式也是如此,因为未定义log(0)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM