Say we have an 8-byte 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.
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). 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). If the result is one I right shifted one bit for result and added 128(1000 000).
For position I initialized p = -1
in case number is zero. Otherwise, assign first index of `> 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.
You can shift the long by 8 bits and look at each byte independently (ie check if the byte == 0). Using the index of the byte, you can set the value in the resulting byte by shifting a 1 into that bit index.
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). 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. 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.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.