简体   繁体   English

Bit twiddling:从ulong,获取表示哪些字节非零的位掩码

[英]Bit twiddling: From ulong, get bitmask representing which bytes were non-zero

Say we have an 8-byte ulong. 假设我们有一个8字节的ulong。 For each byte, we want to know whether it is zero or non-zero. 对于每个字节,我们想知道它是零还是非零。 The desired result is a byte, whose 8 bits represent the "non-zeroness" of the original 8 bytes. 期望的结果是一个字节,其8位表示原始8字节的“非零”。

Is there a name for this operation or set of operations? 是否有此操作或操作集的名称?

How can we achieve this very efficiently? 我们如何才能非常有效地实现这一目 An ideal solution would be branchless. 理想的解决方案是无分支。

As an alternate requirement, a useful answer would be the position of the first non-zero byte. 作为替代要求,有用的答案是第一个非零字节的位置。 Eg if the first non-zero byte is the third one, the answer would be 2 (0-based index). 例如,如果第一个非零字节是第三个,则答案为2(基于0的索引)。 I realize this can be approached by counting the leading zeros of the initial requirement's answer, but perhaps this will allow a shortcut. 我意识到这可以通过计算初始需求的答案的前导零来实现,但也许这将允许一个捷径。

This might help - 这可能有所帮助 -

    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}");
    }

What I have done is bitwise ANDed every byte of input 8 byte number with 255(1111 1111). 我所做的是将输入8字节数的每个字节与255(1111 1111)进行逐位AND运算。 If the result is one I right shifted one bit for result and added 128(1000 000). 如果结果为1,我右移一位用于结果并添加128(1000 000)。

For position I initialized p = -1 in case number is zero. 对于位置I,在情况编号为零的情况下初始化p = -1 Otherwise, assign first index of `> 0'. 否则,指定第一个索引“> 0”。

There are lot of optimization possible like comparing input number to zero and if true simply return 0 for result and -1 for position. 有很多优化可能比如将输入数比较为零,如果为真,则只返回0表示结果,-1表示位置。

You can shift the long by 8 bits and look at each byte independently (ie check if the byte == 0). 您可以将长位移8位并独立查看每个字节(即检查字节== 0)。 Using the index of the byte, you can set the value in the resulting byte by shifting a 1 into that bit index. 使用字节的索引,可以通过将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;
    }

I have a feeling that there is a purely math-based approach to this, but I can't seem to suss it out. 我觉得有一种纯粹基于数学的方法,但我似乎无法理解它。 Otherwise, the most efficient way to do this would be with a loop and some bit-wise comparisons: 否则,最有效的方法是使用循环和一些逐位比较:

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;
}

The mask is a preconfigured value where every bit in a single byte is 1 (255 in decimal, FF in hexadecimal). 掩码是一个预先配置的值,其中单个字节中的每个位都是1(十进制为255,十六进制为FF)。 You offset the mask by i * 8 to get it to cover the nth byte of the input and then use a bitwise-AND to get the value of that byte. 您将掩码偏移i * 8以使其覆盖输入的第n个字节,然后使用按位AND来获取该字节的值。 All you need to do is check if that byte value is non-zero, and if it is, set the corresponding bit of the result byte to 1. (This can be done with either an addition or a bitwise-OR, so I opted to go the OR route to keep with the bitwise theme.) 您需要做的就是检查该字节值是否为非零,如果是,则将结果字节的相应位设置为1.(这可以通过加法或按位OR完成,因此我选择了去OR路线以保持按位主题。)

https://dotnetfiddle.net/EA7NRw https://dotnetfiddle.net/EA7NRw

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

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