C# C语言中的Java Integer.highestOneBit#

C# C语言中的Java Integer.highestOneBit#,c#,bit-manipulation,C#,Bit Manipulation,我一直在努力寻找一个完全替代C#中Java的Integer.highestOneBit(int) 我甚至试着找到它的源代码,但都没有用 JavaDocs告诉我们这个函数: 返回一个int值,该值最多包含一个一位,位于指定int值中最高阶(“最左边”)一位的位置 那么我该如何在C#中实现这一点呢?非常感谢您提供的任何帮助或链接/重定向。提供了一个可以在C#中工作的实现,只需进行一些修改: public static uint highestOneBit(uint i) { i |= (i

我一直在努力寻找一个完全替代C#中Java的
Integer.highestOneBit(int)

我甚至试着找到它的源代码,但都没有用

JavaDocs告诉我们这个函数:

返回一个int值,该值最多包含一个一位,位于指定int值中最高阶(“最左边”)一位的位置

那么我该如何在C#中实现这一点呢?非常感谢您提供的任何帮助或链接/重定向。

提供了一个可以在C#中工作的实现,只需进行一些修改:

public static uint highestOneBit(uint i) 
{
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >>  16);
    return i - (i >> 1);
}

它基本上用1s填充低于最高位的所有位,然后删除除最高位以外的所有位

示例(仅使用16位而不是32位):


您可以为
int
类型编写自己的扩展方法:

public static class Extensions
{
    public static int HighestOneBit(this int number)
    {
        return (int)Math.Pow(2, Convert.ToString(number, 2).Length - 1);
    }
}
因此,它可以用作

int number = 170;
int result = number.HighestOneBit(); //128
或者直接

int result = 170.HighestOneBit(); //128
下面是它的工作原理:


ToString(number,2)
以二进制形式写入我们的数字(例如:10101010代表170)。然后,我们使用第一位位置(长度-1)来计算
2^(第一位位置)
的值,在本例中为128。最后,由于
Math.Pow
返回一个
double
,我们将其向下转换为
int

更新:.NET Core 3.0引入,它直接映射到底层CPU的位前导零计数指令,因此非常高效

public static uint highestOneBit(uint i)
{
返回i==0?0:1;
v |=v>>2;
v |=v>>4;
v |=v>>8;
v |=v>>16;
v++;//现在v是2的下一个幂
v>>=1;//获取2的上一次幂
}
:

public static uint highestOneBit(uint v)
{
常量int multipledBruijnbitPosition[32]=
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |=v>>1;
v |=v>>2;
v |=v>>4;
v |=v>>8;
v |=v>>16;
返回1>27];
}

这是一种对位执行操作的非常昂贵的方法。@JLRishe是的,它是。但至少您不必从
uint
来回转换。除非连续执行超过1000万次,否则差异并不明显。但我认为位移位也很昂贵:(@AmatuerDev在500万次迭代的基准测试中,这些位移位的成本大约要低17倍。在大约100k次迭代时,它会变得很明显,执行起来可能需要几毫秒。@Pierre Luccineault如果使用位,通常应该使用无符号值。我的答案可以用
int
而不是
uint
很好,但是它会为使用第16位的值生成不正确的结果(并且您当前确实会为这些值生成不正确的结果)。刚刚根据@Pierre Luc的答案测试了此方法的输出。它保持不变。因此我猜这也是一个有效的实现。从长远来看,这将是理想的方法。我添加了此函数作为处理UINT上highestOneBit操作的重载。为什么只
I |=(I>>8);
对于大于16位且具有零字节的值(如0x02300000@LưuVĩnhPhúc我的错误。我错误地认为int是16位的。你总能在GrepCode.com上找到任何标准Java库的源代码。示例:
int result = 170.HighestOneBit(); //128