我正在寻找C#中最快的方法来将值舍入到最接近的2的幂。 我已经发现,如果使用像这样的按位运算符,最好的方法是将值舍入到下一个2的幂。
int ToNextNearest(int x)
{
if (x < 0) { return 0; }
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}
但是这给了下一个最接近而不是最近的,我想只有最近的2的幂。 这是一种简单的方法。
int ToNearest(int x)
{
Math.Pow(2, Math.Round(Math.Log(x) / Math.Log(2)));
}
但是有没有一个更好的优化版本找到最接近的两个值?
非常感谢。
答案 0 :(得分:7)
当然,最好的方法是使用您的按位例程来查找下一个2的幂,然后将该结果除以2。这为您提供了之前的两个幂。然后,一个简单的比较将告诉你哪两个更接近。
int ToNearest(int x)
{
int next = ToNextNearest(x);
int prev = next >> 1;
return next - x < x - prev ? next : prev;
}
未经测试的代码,但您明白了。
答案 1 :(得分:1)
这个怎么样:
int ToNearest(int val, int pow)
{
if (pow < 0) return 0;
if (pow == 0) return val;
if (val & (1 << (pow - 1))) {
return ((val >> pow) + 1) << pow;
} else {
return (val >> pow) << pow;
}
}
答案 2 :(得分:0)
尚未测试,但我认为这可行
int ToNearest(value x)
{
int num = 0;
for(int i=1; i < 65; i++)
{
int cur = Math.Abs(value - 0<<i);
if(Math.Abs(value - 0<<i) < Math.Abs(value - num))
num = cur;
else if(num != 0) break;
}
return num;
}
答案 3 :(得分:0)
这是@john的建议解决方案的完整实现,如果值正好在下一个和前一个2的幂之间,它将会向上舍入。
public static int RoundToNextPowerOfTwo(int a)
{
int next = CeilToNextPowerOfTwo(a);
int prev = next >> 1;
return next - a <= a - prev ? next : prev;
}
public static int CeilToNextPowerOfTwo(int number)
{
int a = number;
int powOfTwo = 1;
while (a > 1)
{
a = a >> 1;
powOfTwo = powOfTwo << 1;
}
if (powOfTwo != number)
{
powOfTwo = powOfTwo << 1;
}
return powOfTwo;
}
答案 4 :(得分:0)
由于C#需要IEEE754浮点数,因此在任何不能模拟浮点函数的平台上可能有更快的方法:
int ToNearestPowerOf2(int x) =>
1 << (int)(BitConverter.DoubleToInt64Bits(x + x/3) >> 52) - 1023;
理由:
x + x/3
最接近2的幂,基本上是* 4/3
(BitConverter.DoubleToInt64Bits(x) >> 52) - 1023
采用浮点指数(ln2(x))
1 << x
基数为2的指数函数
该函数显然需要x的正值。 0不会起作用,因为2的最接近的幂是-∞, 负值具有复数对数。
这是否是最快的方式可能在很大程度上取决于JIT优化器从代码中挤出的内容,更具体地说是它如何处理DoubleToInt64Bits中的硬指针。这可能会阻止其他优化。
您不必使用任何比较来获得最接近的2次幂。由于2的所有幂都由相同因子分开,因此舍入点始终为下一次幂的3/4 2(即确切地设置最顶部的2位)。因此乘以倒数然后截断就可以完成这项工作。
答案 5 :(得分:0)
我正在使用这个
public static int CeilPower2(int x)
{
if (x < 2) {
return 1;
}
return (int) Math.Pow(2, (int) Math.Log(x-1, 2) + 1);
}
public static int FloorPower2(int x)
{
if (x < 1) {
return 1;
}
return (int) Math.Pow(2, (int) Math.Log(x, 2));
}
答案 6 :(得分:0)
在.Net Core上,执行此操作的最快方法可能是使用内部函数:
private static int NearestPowerOf2(uint x)
{
return 1 << (sizeof(uint) * 8 - BitOperations.LeadingZeroCount(x - 1));
}
在支持LZCNT指令的CPU上,它只有6条CPU指令,没有分支。