位旋转:从ulong中获取表示哪些字节非零的位掩码

时间:2019-07-10 14:59:32

标签: c# bit-manipulation bitmask

说我们有一个8字节的ulong。对于每个字节,我们想知道它是零还是非零。所需的结果是一个字节,其8位代表原始8个字节的“非零”。

此操作或一组操作有名称吗?

我们如何才能非常有效地实现这一目标?理想的解决方案是无分支。

作为替代要求,一个有用的答案将是第一个非零字节的位置。例如。如果第一个非零字节是第三个字节,则答案为2(基于0的索引)。我意识到可以通过计算初始需求的答案的前导零来解决这个问题,但这也许会提供捷径。

3 个答案:

答案 0 :(得分:1)

这可能有帮助-

    private void Evaluate(ulong n)
    {
        ulong f = 255;
        int r = 0, p = -1;
        for (int i = 0; i < 8; i++)
        {
            r >>= 1;
            var t = n & f;
            if (t > 0)
            {
                r += 128;
                if (p < 0)
                    p = i;
            }
            f <<= 8;
        }
        Console.WriteLine($"Resulting byte: {r}");
        Console.WriteLine($"Position: {p}");
    }

我所做的是将输入的8个字节的每个字节与255(1111 1111)按位与。如果结果为1,则我将结果右移一位并加128(1000 000)。

对于位置,我在数字为零的情况下初始化了p = -1。否则,将第一个索引指定为“> 0”。

可以进行很多优化,例如将输入数字与零进行比较,如果为true,则仅对结果返回0,对位置返回-1。

答案 1 :(得分:1)

您可以将long移位8位,然后独立查看每个字节(即检查字节== 0)。使用字节的索引,可以通过将1移入该位索引来设置结果字节中的值。

    private byte TestULong(ulong value)
    {
        byte result = 0;
        for (int i = 0; i < 8; i++)
        {
            var test = (byte)(value >> (i * 8));
            if (test != 0)
            {
                result = (byte)(result | (1 << i));
            }
        }
        return result;
    }

答案 2 :(得分:1)

我有一种纯粹基于数学的方法,但是我似乎无法对此表示怀疑。否则,最有效的方法是使用循环和一些按位比较:

public static byte Evaluate(ulong n) {
    ulong mask = 0xFF;
    byte result = 0;
    for (int i = 0; i < 8; i++) {
        if ((n & (mask << (i * 8))) != 0) {
            result |= (byte)(1 << i);
        }
    }
    return result;
}

掩码是一个预配置的值,其中单个字节中的每个位均为1(十进制为255,十六进制为FF)。您将掩码偏移i * 8以使其覆盖输入的第n个字节,然后使用按位与运算符获取该字节的值。您需要做的就是检查该字节值是否为非零,如果是,则将结果字节的相应位设置为1。(这可以通过加法或按位或运算完成,因此我选择了走OR路线以保持按位主题。)

https://dotnetfiddle.net/EA7NRw