2009-09-30 18 views
11

Sto leggendo bit da una bitmap monocromatica. Sto memorizzando ogni 16 bit in un short nell'ordine inverso. Se il bit nella bitmap è nero, memorizzare un 1. Se il bianco, memorizzare uno 0.Spostamento del bit di segno in .NET

Esempio: per bitmap: BBBW BBBW BBBW wwww
mio breve è: 0000 0111 0111 0111

Il primo modo ho provato a fare questo è stato:

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

Dopo un incarico e lo spostamento, ho avuto l'aspettavo -32768 (1000 0000 0000 0000).
Dopo la seconda volta ho ottenuto -16384 (1100 0000 0000 0000).

Ho modificato il mio codice per utilizzare ushort e modificato la riga if in s |= (ushort)Math.Pow(2, 15); e ora funziona.

La mia domanda è: perché il bit di segno non si sposta in .NET? C'è un modo per spostare il bit del segno?

+0

per mantenerlo efficiente, si può semplicemente fare m 'ushort' invece di 'breve', o iniziare dal bit più a destra e spostare a sinistra (solo per evitare di utilizzare Math.pow). – Groo

risposta

27

In C#, i turni sono aritmetiche turni (in contrasto con turni logici). In uno spostamento aritmetico a destra, il bit di segno viene spostato sulla fascia sinistra sul, in modo che il segno del numero sia riprodotta. Un diritto spostamento equivale a dividere per 2:

alt text

Se si desidera un logica turno (senza estensione del segno), uso numeri senza segno:

alt text

+0

Vale la pena notare che "utilizzare numeri non firmati" non deve essere per l'intero metodo se non si adatta per qualche altra ragione . 'm = (breve) ((ushort) >> 1)' il compilatore dovrebbe emettere il 'shr.un' per lo spostamento senza segno senza alcuna operazione di cast; i calchi che esistono nel C# non ci sono nel CIL, semplicemente sa che non lo vuoi trattare a quel punto. –

3

destro spostando firmato interi in C# riempie i bit a sinistra con il bit segno. In effetti, il risultato del giusto spostamento di un intero con segno da un singolo bit equivale a dividerlo per 2.

Puoi trovare questo tipo di spostamento a destra anche in altri luoghi. Ad esempio, l'assembly x86 fornisce due istruzioni distinte, sar (che riempie i bit di sinistra con il bit di segno) e shr (che riempie i bit di sinistra con zero).

Se non si desidera questo comportamento in C#, sarà necessario utilizzare tipi non firmati durante lo spostamento.

1

La risposta breve alla tua domanda, come hai scoperto, è quella di utilizzare numeri interi senza segno per evitare di introdurre il bit del segno, e questo è tutto a posto. Tuttavia fare considerare quanto segue

Optimization suggerimento

Supponendo che si deve fare molta tali conversioni (tipicamente ci sono un sacco di pixel in una bitmap), è consigliabile utilizzare un array di 256 byte che fornirebbe direttamente la versione invertita del modello di bit (o qualunque sia la conversione) per un byte completo. Quindi indicizzando direttamente questa matrice, con il valore hi o low byte della parola a 16 bit, si ottengono i risultati per tutti gli 8 bit. In alcuni casi in cui il tempo/prestazioni è un premio (e lo spazio è disponibile ...) è anche possibile utilizzare una dimensione dell'array a 64k, elaborando una parola intera alla volta.

Data la conversione specificata nel tuo esempio, avresti la matrice valori precalcolati essere qualcosa di simile:

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

Sto convertendo l'immagine da visualizzare su un dispositivo che ne ha bisogno in segmenti invertiti a 16 bit come questo: bitmap = 0,1,2, ..., 62,63. device = 15..0, 31..16, 47..32, 63..48 – Dinah

4

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

"L'operatore >> sposta i bit di destra espressione1 per il numero di bit specificato in expression2 Il bit di segno di expression1 viene utilizzato per riempire le cifre da sinistra. Le cifre spostate a destra vengono scartate Il tipo di dati di expression1 determina il tipo di dati restituito da questo operatore."

2

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

... firmato interi usa il bit più significativo per determinare se il valore di una variabile è positivo o negativo e che i bit rimanenti utilizzano notazione complemento a due per valori negativi La massima bit ordine sarebbe normalmente considerato come il bit di overflow per un'operazione di spostamento a sinistra. Per consentire ciò, C# comprende che questo bit non deve essere regolato per i tipi di dati firmati e che i numeri negativi devono essere spostati di conseguenza. Così il cambiamento funziona sia per valori negativi che positivi.

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