2009-03-20 3 views

risposta

13
for (i = 10 ; i-- > 0 ;) 
    result_array[i] = byte_array[i] & byte_mask[i]; 
  • A ritroso precarica processore cache-linee.
  • Includendo il decremento nel confronto è possibile salvare alcune istruzioni.

Questo funzionerà per tutti gli array e processori. Tuttavia, se sai che i tuoi array sono allineati alle parole, un metodo più veloce è quello di trasmettere a un tipo più grande e fare lo stesso calcolo.

Ad esempio, supponiamo n=16 anziché n=10. Allora questo sarebbe molto più veloce:

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]; 

(naturalmente è necessario un tipo adatto uint32_t, e se n non è una potenza di 2 è necessario ripulire l'inizio e/o fine in modo che il 32- bit bit è allineato.)

Variazione: la domanda richiede specificamente che i risultati vengano posizionati in un array separato, tuttavia sarebbe quasi certamente più rapido modificare l'array di input sul posto.

+0

Aspetta, il prefetcher della cache funziona meglio al contrario? Pensavo che fosse prefissato solo andando avanti. – Crashworks

+2

Preoccuparsi del precaricamento delle linee della cache del processore sembra una severa ottimizzazione prematura. – Trent

+5

@Trent - il * punto * della domanda è l'ottimizzazione. Anche andare all'indietro non è più lento, quindi potresti anche farlo. @Crashworks: ricorda che le linee della cache sono allineate, in genere su enormi limiti, quindi in genere deve inserire byte prima di quelli che stai richiedendo. –

5

Se volete renderlo più veloce, assicurarsi che byte_array ha lunghezza che è multiplo di 4 (8 su macchine a 64-bit), e poi:

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]; 
} 

Questo è molto più veloce di farlo byte per byte.

(Si noti che questo è sul posto mutazione,., Se si desidera mantenere anche la byte_array originale, allora dovrete, ovviamente, per memorizzare i risultati in un altro array invece)

+0

10/4 == 2, quindi questo elabora solo 8 caratteri. Inoltre, su alcune architetture non-x86 questo potrebbe provocare un errore del bus a causa di accessi di memoria non allineati. – bk1e

+0

bk1e: hai ragione, io <10/4 è sbagliato. Anche il commento sull'errore del bus è corretto. Modificherò la risposta. –

+0

Se non è un multiplo di 4/8, usa il dispositivo di duff :) – 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; 

Ora INT_array per il mascheramento. Questo potrebbe funzionare sia per processori a 32 bit che a 64 bit.

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]; 
} 

Prova questo codice potrebbe anche sembrare pulito.

+0

Grazie per aver scritto il codice di esempio :) – alvatar