2009-09-30 12 views
11

Estoy leyendo bits de un mapa de bits monocromo. Estoy almacenando cada 16 bits en un short en el orden inverso. Si el bit del mapa de bits es negro, almacenar un 1. Si el blanco, almacenar una Ej 0.Cambiando el bit de signo en .NET

: de mapa de bits: BBBW BBBW BBBW wwww
mi corta es: 0000 0111 0111 0111

La primera forma traté de hacer esto era:

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

Después de una asignación y desplazamiento, me la esperaba -32768 (1000 0000 0000 0000).
Después de la 2da vez que recibí -16384 (1100 0000 0000 0000).

He cambiado mi código para usar ushort y he cambiado la línea if al s |= (ushort)Math.Pow(2, 15); y ahora funciona.

Mi pregunta es: ¿por qué el bit de signo no cambiará en .NET? ¿Hay alguna manera de cambiar el bit de signo?

+0

para mantenerlo eficiente, usted podría simplemente hacer m 'ushort' en lugar de 'corto', o empezar desde el bit más a la derecha y la desviación a la izquierda (sólo para evitar el uso de Math.pow). – Groo

Respuesta

27

En C#, los cambios son aritméticas turnos (en contraste con los cambios lógicos). En un desplazamiento aritmético a la derecha, el bit de signo se desplaza en la izquierda, por lo que el signo del número se conserva. A la derecha cambio es equivalente a dividir por 2:

alt text

Si desea una lógica turno (sin extensión de signo), uso de números sin signo:

alt text

+0

Merece la pena señalar que "usar números sin signo" no tiene que ser para todo el método si no se adapta por alguna otra razón . 'm = (short) ((ushort) >> 1)' haría que el compilador emitiera el 'shr.un' para el desplazamiento sin signo sin operaciones de conversión; los moldes que existen en el C# no están en el CIL, simplemente sabe que quieres tratarlo sin firmar en ese momento. –

3

correr a la derecha firmaron enteros en C# llena los bits de la izquierda con el bit de signo . Efectivamente, el resultado de desplazar a la derecha un entero con signo por un solo bit es equivalente a dividirlo por 2.

Puede encontrar este tipo de desplazamiento a la derecha en otros lugares también. Por ejemplo, el ensamblaje x86 proporciona dos instrucciones distintas, sar (que llena los bits de la izquierda con el bit de signo) y shr (que llena los bits de la izquierda con cero).

Si no desea este comportamiento en C#, tendrá que usar tipos sin firmar al cambiar.

1

La respuesta breve a su pregunta, como descubrió es usar un entero sin signo para evitar introducir el bit de signo, y eso está bien. Sin embargo hacer considerar el siguiente

Optimización pista

Asumiendo que usted tiene que hacer una gran cantidad de este tipo de conversiones (por lo general hay una gran cantidad de píxeles en un mapa de bits), se debe considerar el uso de una matriz de 256 bytes que proporcionaría directamente la versión invertida del patrón de bits (o cualquiera que sea la conversión) para un byte completo. Luego, al indexar directamente esta matriz, ya sea con el valor alto o bajo de la palabra de 16 bits, se obtienen los resultados para los 8 bits. En algunos casos en los que el tiempo/rendimiento es escaso (y hay espacio disponible ...) incluso puede usar un tamaño de matriz de 64k, procesando una palabra completa a la vez.

Dada la conversión especificada en su ejemplo, tendría la matriz valores precalculados ser algo como:

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

Estoy convirtiendo la imagen que se mostrará en un dispositivo que lo necesita en segmentos invertidos de 16 bits como este: bitmap = 0,1,2, ..., 62,63. dispositivo = 15..0, 31..16, 47..32, 63..48 – Dinah

4

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

"El operador >> desplaza los bits de la derecha expresión1 por el número de bits especificado en la expresión 2. El signo de expresión1 se utiliza para rellenar los dígitos de la izquierda. Los dígitos desplazados a la derecha se descartan. El tipo de datos de expresión1 determina el tipo de datos devuelto por este operador."

2

por http://www.blackwasp.co.uk/CSharpShiftOperators.aspx

... enteros con signo utilizan el bit más alto a fin de determinar si el valor de una variable es positivo o negativo y que los bits restantes utilizan la notación de complemento a dos para los valores negativos el bit de orden más alto normalmente se consideraría como el bit de desbordamiento para una operación de desplazamiento a la izquierda. Para permitir esto, C# entiende que este bit no se debe ajustar para los tipos de datos firmados y que los números negativos se deben desplazar en consecuencia. Por lo tanto, el cambio funciona tanto para valores negativos como positivos.

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