让我们开始吧,
我们做一个循环,检查我们是否有'1',如果有,我们想把那个位添加到结果中……
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
byte current = 1;
for (var index = 0; index < chars.Length; index++)
{
if (chars[index] == '1')
{
result += current;
}
current *= 2;
}
Console.WriteLine(result); // 198
让我们检查…198 二进制是…11000110。啊,你看,我假设第一个索引是最不有价值的位,因此我把它反过来了。所以,让我们翻转它。
顺便说一句,我将result 声明为byte,这也预设了数组最多有8 个项目。对于以下代码,我假设数组正好有 8 个项目。
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
byte current = 1;
for (var index = 0; index < chars.Length; index++)
{
if (chars[index] == '1')
{
result += current;
}
current *= 2;
}
Console.WriteLine(result); // 99
检查,99 是二进制的1100011。让我们把这个假设编成代码,好吗?
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
if (chars.Length != 8)
{
throw new ArgumentOutOfRangeException();
}
byte result = 0;
byte current = 128;
for (var index = 0; index < 8; index++)
{
if (chars[index] == '1')
{
result += current;
}
current /= 2;
}
Console.WriteLine(result);
好的,我们现在可以反转循环以进行微优化。
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
if (chars.Length != 8)
{
throw new ArgumentOutOfRangeException();
}
byte result = 0;
byte current = 1;
for (var index = 7; index >= 0; index--)
{
if (chars[index] == '1')
{
result += current;
}
current *= 2;
}
Console.WriteLine(result);
让我们进行二进制移位而不是乘以 2。
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
if (chars.Length != 8)
{
throw new ArgumentOutOfRangeException();
}
byte result = 0;
byte current = 1;
for (var index = 7; index >= 0; index--)
{
if (chars[index] == '1')
{
result += current;
}
current <<= 1;
}
Console.WriteLine(result);
让我们再加一个假设:数组只有'0'和'1':
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
if (chars.Length != 8)
{
throw new ArgumentOutOfRangeException();
}
for (var index = 7; index >= 0; index--)
{
if (chars[index] != '0' && chars[index] != '1')
{
throw new ArgumentOutOfRangeException();
}
}
byte result = 0;
byte current = 1;
for (var index = 7; index >= 0; index--)
{
if (chars[index] == '1')
{
result += current;
}
current <<= 1;
}
Console.WriteLine(result);
当然,如果您可以通过其他方式保证,您可以删除验证。我假设你会这样做。
接下来,让我们注意,当我们将char 转换为int(这是一个安全的转换)时,'0' 将是48 并且'1' 将是49。这些值仅在最后一位(最低值)有所不同,而该位就是我们想要的值。
知道了,我可以直接设置位:
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
byte current = 1;
for (var index = 7; index >= 0; index--)
{
result |= unchecked((byte)(current * (chars[index] & 1)));
current <<= 1;
}
Console.WriteLine(result);
在上面的代码中,我使用二进制掩码 & 1 从字符代码(48 或 49)中提取 0 或 1。然后乘以current。因此,如果找到1,我们设置当前位,如果找到0,则不设置。
嗯,我们可以直接shift,给我们保存一个变量。
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
for (var index = 7; index >= 0; index--)
{
result |= unchecked((byte)((1 << (7 - index)) * (chars[index] & 1)));
}
Console.WriteLine(result);
在上面的代码中,我没有保留current,而是在每次迭代时计算它。
我们可以在没有乘法的情况下做到这一点。我们改用0 或1。
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
for (var index = 7; index >= 0; index--)
{
result |= unchecked((byte)(((chars[index] & 1) << (7 - index))));
}
Console.WriteLine(result);
在上面,我转移了来自字符代码的0或1。为我们节省了一个乘法。
让我们展开 for,我们知道总是有 8 次迭代。
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
result |= unchecked((byte)(((chars[7] & 1) << (7 - 7))));
result |= unchecked((byte)(((chars[6] & 1) << (7 - 6))));
result |= unchecked((byte)(((chars[5] & 1) << (7 - 5))));
result |= unchecked((byte)(((chars[4] & 1) << (7 - 4))));
result |= unchecked((byte)(((chars[3] & 1) << (7 - 3))));
result |= unchecked((byte)(((chars[2] & 1) << (7 - 2))));
result |= unchecked((byte)(((chars[1] & 1) << (7 - 1))));
result |= unchecked((byte)(((chars[0] & 1) << (7 - 0))));
Console.WriteLine(result);
我们可以稍微简化一下:
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = 0;
result |= unchecked((byte)(((chars[7] & 1) << 0)));
result |= unchecked((byte)(((chars[6] & 1) << 1)));
result |= unchecked((byte)(((chars[5] & 1) << 2)));
result |= unchecked((byte)(((chars[4] & 1) << 3)));
result |= unchecked((byte)(((chars[3] & 1) << 4)));
result |= unchecked((byte)(((chars[2] & 1) << 5)));
result |= unchecked((byte)(((chars[1] & 1) << 6)));
result |= unchecked((byte)(((chars[0] & 1) << 7)));
Console.WriteLine(result);
我们如何在一次操作中执行此操作并在最后转换为byte?
char[] chars = new char[] {'0', '1', '1', '0', '0', '0' , '1', '1'};
byte result = unchecked((byte)(
((chars[7] & 1) << 0)
| ((chars[6] & 1) << 1)
| ((chars[5] & 1) << 2)
| ((chars[4] & 1) << 3)
| ((chars[3] & 1) << 4)
| ((chars[2] & 1) << 5)
| ((chars[1] & 1) << 6)
| ((chars[0] & 1) << 7)
));
Console.WriteLine(result);
太棒了!因此,我们从字符代码中提取0 或1(使用掩码),并将其移动到字节中的位置,将它们放在一起,我们就得到了结果。希望它的工作原理和我们如何到达那里都有意义。