2009-03-20 12 views
9

Ich habe einen C-Array wie zu machen:Was ist der effizienteste Weg, bitweise Operationen in einem C-Array

char byte_array[10]; 

und eine anderen, die als Maske wirkt:

char byte_mask[10]; 

Ich mag würde zu Erhalten Sie ein anderes Array, das das Ergebnis von dem ersten plus dem zweiten ist, das eine bitweise Operation für jedes Byte verwendet.

Was ist der effizienteste Weg, dies zu tun?

danke für Ihre Antworten.

Antwort

13
for (i = 10 ; i-- > 0 ;) 
    result_array[i] = byte_array[i] & byte_mask[i]; 
  • rückwärts vorge Lasten Prozessor-Cache-Linien.
  • Mit dem Dekrement im Vergleich können einige Anweisungen gespeichert werden.

Dies funktioniert für alle Arrays und Prozessoren. Wenn Sie jedoch wissen, dass Ihre Arrays wortorientiert sind, besteht eine schnellere Methode darin, in einen größeren Typ zu konvertieren und die gleiche Berechnung durchzuführen.

Zum Beispiel sagen wir n=16 anstelle von n=10. Dann wäre dies viel schneller sein:

uint32_t* input32 = (uint32_t*)byte_array; 
uint32_t* mask32 = (uint32_t*)byte_mask; 
uint32_t* result32 = (uint32_t*)result_array; 
for (i = 4 ; i-- > 0 ;) 
    result32[i] = input32[i] & mask32[i]; 

(Natürlich kann man einen richtigen Typen für uint32_t benötigen, und wenn n keine Potenz von 2 Sie müssen den Anfang, um aufzuzuräumen und/oder endet, so dass die 32- Bit-Zeug ist ausgerichtet.)

Variation: Die Frage fordert speziell für die Ergebnisse in einem separaten Array platziert werden, aber es wäre fast sicher schneller das Eingangs-Array in-Place zu ändern.

+0

Warte, arbeitet der Cache-Prefetcher besser rückwärts? Ich dachte, es würde nur vorwärts gehen. – Crashworks

+2

Die Sorge über das Vorladen von Prozessor-Cache-Zeilen scheint eine schwere vorzeitige Optimierung zu sein. – Trent

+5

@Trent - der * Punkt * der Frage ist Optimierung. Auch rückwärts gehen ist nicht langsamer, also könnte es genauso gut sein. @Crashworks - denken Sie daran, dass Cache-Zeilen ausgerichtet sind, typischerweise an massiven Grenzen, so dass es in der Regel Bytes in Bytes vor denen, die Sie fordern, ziehen muss. –

5

Wenn Sie es machen wollen schneller, stellen Sie sicher, dass byte_array Länge hat, die Vielfaches von 4 (8 auf 64-Bit-Maschinen) ist, und dann:

char byte_array[12]; 
char byte_mask[12]; 
/* Checks for proper alignment */ 
assert(((unsigned int)(void *)byte_array) & 3 == 0); 
assert(((unsigned int)(void *)byte_mask) & 3 == 0); 
for (i = 0; i < (10+3)/4; i++) { 
    ((unsigned int *)(byte_array))[i] &= ((unsigned int *)(byte_mask))[i]; 
} 

Das ist viel schneller, als es Byte tun pro Byte.

(Beachten Sie, dass diese an Ort und Stelle ist Mutation;., Wenn Sie die ursprüngliche byte_array auch behalten möchten, dann speichern Sie müssen natürlich die Ergebnisse in einem anderen Array statt)

+0

10/4 == 2, so verarbeitet dies nur 8 Zeichen. Zusätzlich kann dies bei einigen Nicht-x86-Architekturen einen Busfehler aufgrund nicht ausgerichteter Speicherzugriffe auslösen. – bk1e

+0

bk1e: Sie haben Recht, ich <10/4 ist falsch. Der Kommentar zum Busfehler ist ebenfalls korrekt. Ich werde die Antwort bearbeiten. –

+0

Wenn es kein Vielfaches von 4/8 ist, benutze duffs Gerät :) – Brian

1
\#define CHAR_ARRAY_SIZE (10) 
\#define INT_ARRAY_SIZE  ((CHAR_ARRAY_SIZE/ (sizeof (unsigned int)) + 1) 

typedef union _arr_tag_ { 

    char   byte_array [CHAR_ARRAY_SIZE]; 
    unsigned int int_array [INT_ARRAY_SIZE]; 

} arr_tag; 

int_array nun zur Maskierung. Dies funktioniert möglicherweise für 32-Bit- und 64-Bit-Prozessoren.

arr_tag arr_src, arr_result, arr_mask; 

for (int i = 0; i < INT_ARRAY_SIZE; i ++) { 
    arr_result.int_array [i] = arr_src.int_array[i] & arr_mask.int_array [i]; 
} 

Versuchen Sie dies, Code könnte auch sauber aussehen.

+0

Danke für das Schreiben des Beispielcodes :) – alvatar

Verwandte Themen