在.NET中移动符号位

我正在从单色位图中读取位。 我以相反的顺序将每16位存储在一个short中。 如果位图中的位为黑色,则存储1.如果为白色,则存储0。

例如:对于位图:bbbw bbbw bbbw wwww
我的简称是:0000 0111 0111 0111

我尝试这样做的第一种方式是:

 short m; // ... Color c = bmp.GetPixel(j, i); if (cR == Color.Black) m |= short.MinValue; m >>= 1; // ... 

经过一次任务和class次后,我得到了预期的-32768(1000 0000 0000 0000)。
第二次我得到-16384(1100 0000 0000 0000)。

我改变了我的代码以使用ushort并将if行更改为s |= (ushort)Math.Pow(2, 15); 现在它的工作原理。

我的问题是:为什么标志位不会在.NET中发生变化? 有没有办法改变标志位?

在C#中,移位是算术移位(与逻辑移位相反)。 在右移算术中,符号位在左侧移入,因此保留了数字的符号。 右移相当于除以2:

替代文字

如果您想要逻辑移位(无符号扩展名),请使用无符号数字

替代文字

http://msdn.microsoft.com/en-us/library/k2ay192e.aspx

“>>”运算符将表达式1的位右移表达式2中指定的位数。表达式1的符号位用于填充左侧的数字。向右移位的数字将被丢弃。表达式1的数据类型确定此运算符返回的数据类型。“

在C#中右移有符号整数用符号位填充左边的 。 实际上,将有符号整数右移一位的结果相当于将其除以2。

你也可以在其他地方找到这种正确的转变。 例如,x86程序集提供了两个不同的指令, sar (用符号位填充左边的位)和shr (用左边的位填充零)。

如果您不希望在C#中出现此行为,则在转换时必须使用无符号类型。

根据http://www.blackwasp.co.uk/CSharpShiftOperators.aspx

…有符号整数使用最高位来确定变量的值是正还是负,剩余的位使用二进制补码表示负值。最高位通常被认为是左移的溢出位操作。 为了实现这一点,C#理解不应该对有符号数据类型调整该位,并且应该相应地移动负数。 因此,转移适用于负值和正值。

 int value = -240; int halved = value >> 1; // Result = -120 

你发现问题的简短答案是使用无符号整数来避免引入符号位,这一切都很好。 但是请考虑以下内容

优化提示

假设您必须进行大量此类转换(通常位图中有很多像素),您应该考虑使用256字节的数组,这将直接提供位模式的反转版本(或者无论转换可能是什么) be)一个完整的字节。 然后通过直接索引此数组,使用16位字的高或低字节值,可以得到所有8位的结果。 在某些时间/性能非常宝贵(并且空间可用……)的情况下,您甚至可以使用64karrays大小,一次处理一个完整的单词。

鉴于您的示例中指定的转换,您将预先计算的值数组类似于:

  byte[] mirror = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x78, 0xF8, // etc.. 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF };