2010-11-18 9 views

Antwort

11

Verwenden Sie eine Nachschlagetabelle. Es gibt nur 256 mögliche Werte nach XORing, also wird es nicht lange dauern. Anders als bei der izb-Lösung würde ich jedoch nicht vorschlagen, alle Werte manuell einzugeben - berechne die Nachschlagetabelle einmal beim Start mit einer der loopenden Antworten.

Zum Beispiel:

public static class ByteArrayHelpers 
{ 
    private static readonly int[] LookupTable = 
     Enumerable.Range(0, 256).Select(CountBits).ToArray(); 

    private static int CountBits(int value) 
    { 
     int count = 0; 
     for (int i=0; i < 8; i++) 
     { 
      count += (value >> i) & 1; 
     } 
     return count; 
    } 

    public static int CountBitsAfterXor(byte[] array) 
    { 
     int xor = 0; 
     foreach (byte b in array) 
     { 
      xor ^= b; 
     } 
     return LookupTable[xor]; 
    } 
} 

(Sie könnte es eine Erweiterungsmethode, wenn Sie wirklich wollte ...)

Beachten Sie die Verwendung von byte[] im CountBitsAfterXor Methode - Sie konnte Machen Sie es für allgemeinere Zwecke zu einem IEnumerable<byte>, aber das Iterieren über ein Array (das bei der Kompilierung als Array bekannt ist) wird schneller. Wahrscheinlich nur mikroskopisch schneller, aber hey, fragte sie die schnellste Weg :)

würde ich mit ziemlicher Sicherheit tatsächlich es ausdrücken als

public static int CountBitsAfterXor(IEnumerable<byte> data) 

im wirklichen Leben, aber sehen, welche für Sie besser funktioniert .

Beachten Sie auch den Typ der xor Variable als int. Tatsächlich ist kein XOR-Operator für byte Werte definiert, und wenn Sie xor eine byte gemacht hätten, würde es immer noch kompilieren aufgrund der Natur von Compound-Zuweisungsoperatoren, aber es würde bei jeder Iteration eine Umwandlung durchführen - zumindest in der IL.Es ist durchaus möglich, dass das JIT sich darum kümmern würde, aber es gibt keine Notwendigkeit, es sogar zu fragen :)

+0

Danke, auf Code-Beispiel oder Link wartend .. –

+0

Vielen Dank für deine Antwort. –

1

Die folgende Beschreibung ist

int BitXorAndSum(byte[] left, byte[] right) { 
    int sum = 0; 
    for (var i = 0; i < left.Length; i++) { 
    sum += SumBits((byte)(left[i]^right[i])); 
    } 
    return sum; 
} 

int SumBits(byte b) { 
    var sum = 0; 
    for (var i = 0; i < 8; i++) { 
    sum += (0x1) & (b >> i); 
    } 
    return sum; 
} 
+0

Das summiert die Bytes. Ich verstand das OP, dass er wollte, dass die Bits summiert werden? – winwaed

+0

Hallo. Danke für die Antwort. Aber ich brauche Summe von Bits, nicht einfache Summe. Siehe mein Beispiel oben. –

+0

yeah Summe der Bits. –

3

Wie ich es verstanden Sie die Bits jedes XOR zwischen dem linken und rechten Bytes summieren möchten.

for (int b = 0; b < left.Length; b++) { 
    int num = left[b]^right[b]; 
    int sum = 0; 

    for (int i = 0; i < 8; i++) { 
    sum += (num >> i) & 1; 
    } 

    // do something with sum maybe? 
} 
+1

Wenn die Leistung eine Rolle spielt, können Sie die Summe der Bits für jede der 256 möglichen Byte-Kombinationen vorberechnen und in einer Nachschlagetabelle speichern. Ich denke, das würde einen Leistungsgewinn bringen, aber Sie müssten es Benchmarks. – eoldre

2

Ich bin nicht sicher, wenn Sie Summe der Bytes oder der Bits meinen. Um die Bits innerhalb eines Bytes zusammenzufassen, sollte diese Arbeit:

int nSum = 0; 
for (int i=0; i<=7; i++) 
{ 
    nSum += (byte_val>>i) & 1; 
} 

Sie müssten dann die XOR-Verknüpfung und Anordnung um diese Looping, natürlich.

9

Der schnellste Weg wäre wahrscheinlich eine 256-Element-Lookup-Tabelle sein ...

int[] lut 
{ 
    /*0x00*/ 0, 
    /*0x01*/ 1, 
    /*0x02*/ 1, 
    /*0x03*/ 2 
    ... 
    /*0xFE*/ 7, 
    /*0xFF*/ 8 
} 

z.B.

11110000^01010101 = 10100101 -> lut[165] == 4 
+1

+1 Nabbits. Ich habe das gerade gepostet - Deine impliziten Parallelfähigkeiten sind hervorragend :-) –

5

Dies wird häufiger als Bit-Zählung bezeichnet. Dafür gibt es buchstäblich Dutzende verschiedener Algorithmen. Here ist eine Seite, die einige der bekannteren Methoden auflistet. Dazu gibt es sogar CPU-spezifische Anweisungen.

Theoretisch könnte Microsoft eine -Funktion hinzufügen, die JITed mit dem besten Algorithmus für diese CPU-Architektur erhält. Ich würde eine solche Ergänzung begrüßen.

+1

Danke für gute Verbindung. –

0

Eine allgemeine Funktion Bits aussehen zählen kann:

int Count1(byte[] a) 
{ 
    int count = 0; 
    for (int i = 0; i < a.Length; i++) 
    { 
    byte b = a[i]; 
    while (b != 0) 
    { 
     count++; 
     b = (byte)((int)b & (int)(b - 1)); 
    } 
    } 
    return count; 
} 

Je weniger 1-Bit arbeitet, desto schneller dies. Es läuft einfach über jedes Byte und schaltet das niedrigste 1 Bit dieses Bytes um, bis das Byte 0 wird. Die Castings sind notwendig, damit der Compiler aufhört, sich über die Typverbreiterung und -verengung zu beschweren.

Ihr Problem dann unter Verwendung dieser gelöst werden könnte:

int Count1Xor(byte[] a1, byte[] a2) 
{ 
    int count = 0; 
    for (int i = 0; i < Math.Min(a1.Length, a2.Length); i++) 
    { 
    byte b = (byte)((int)a1[i]^(int)a2[i]); 
    while (b != 0) 
    { 
     count++; 
     b = (byte)((int)b & (int)(b - 1)); 
    } 
    } 
    return count; 
} 
1

Es als ulong neu geschrieben werden können und unsafe Zeiger verwenden, aber byte leichter zu verstehen:

static int BitCount(byte num) 
{ 
    // 0x5 = 0101 (bit) 0x55 = 01010101 
    // 0x3 = 0011 (bit) 0x33 = 00110011 
    // 0xF = 1111 (bit) 0x0F = 00001111 
    uint count = num; 
    count = ((count >> 1) & 0x55) + (count & 0x55); 
    count = ((count >> 2) & 0x33) + (count & 0x33); 
    count = ((count >> 4) & 0xF0) + (count & 0x0F); 
    return (int)count; 
} 
+1

Hat ein Tippfehler in der dritten Berechnung, 0xF0 Maske ist falsch, wenn nach der Verschiebung getan, sollte 0x0F Maske verwenden. – Zarat

0

Eine Lookup-Tabelle sollte Seien Sie der schnellste, aber wenn Sie es ohne eine Nachschlagetabelle tun möchten, funktioniert dies für Bytes in nur 10 Operationen.

public static int BitCount(byte value) { 
    int v = value - ((value >> 1) & 0x55); 
    v = (v & 0x33) + ((v >> 2) & 0x33); 
    return ((v + (v >> 4) & 0x0F)); 
} 

Dies ist eine Byte-Version der allgemeinen Funktion Bit Zählung bei Sean Eron Anderson's bit fiddling site beschrieben.

Verwandte Themen