2011-02-01 10 views
5

Ho un buffer circolare di dimensioni fisse (implementato come array): al momento dell'inizializzazione, il buffer viene riempito con il numero massimo specificato di elementi che consente l'uso di un indice di posizione singola per tenere traccia della nostra posizione attuale nel cerchio.Come avvolgere in modo efficiente l'indice di un buffer circolare a dimensione fissa

Che cos'è un modo efficace per accedere a un elemento nel buffer circolare? Ecco la mia soluzione attuale:

int GetElement(int index) 
{ 
    if (index >= buffer_size || index < 0) 
    { 
     // some code to handle the case 
    } 
    else 
    { 
     // wrap the index 
     index = end_index + index >= buffer_size ? (index + end_index) - buffer_size : end_index + index; 
    } 

    return buffer[index]; 
} 

Alcune definizioni:
end_index è l'indice dell'elemento immediatamente dopo l'ultimo elemento nel cerchio (che sarebbe anche essere considerato uguale al START_INDEX, o il primo elemento di il cerchio).
buffer_size è la dimensione massima del buffer.

+0

Quando non è END_INDEX pari a buffer_size? –

+0

@Fred, quando si aggiunge un elemento al buffer circolare ... l'indice si avvolge ogni volta che si supera il buffer_size. – Kiril

+0

@Lirik: mi manca qualcosa. –

risposta

10

Assicurarsi che il buffer sia sempre una potenza di due lunghi e mascherare i bit superiori.

+1

Quindi ... modulo/modulo? : P –

+4

@Johnatan: un'operazione modulo prematuramente ottimizzata, sì. – delnan

+0

@delnan Non so di prematuramente. Mentre personalmente userò il modulo, in realtà è una pratica molto comune avere array come potenze di due per questo motivo. – corsiKa

5

Sarà dipende un po 'sul processore, ma è probabilmente almeno la pena di provare qualcosa di simile return (end_index + index) % buffer_size;

+0

** (1) ** Is' end_index' non uguale a 'buffer_size' (presupponendo una matrice con indice 0)? ** (2) ** Con questo in mente, semplifichiamo questo per 'return (a + n)% n;' - quindi se 'a = -5', e' n = 4', quindi '(a + n) 'yields' -1', che è ancora fuori dai limiti. (cioè, fallisce per 'a <-n'). – mpen

+1

@Mark: sebbene il codice originale implichi la possibilità di numeri negativi, di solito non è consentito a tutti (anche se probabilmente è meglio usare un tipo senza segno per assicurarsi contro di esso). –

+0

Oh ... immagino che la mia situazione sia diversa. Io uso spesso -1 per indicare l'ultimo elemento. – mpen

0

FWIW, si può sempre fare un allineamento parallelo: i = next[i];

Ma, in realtà, ho sempre appena fatto questo: i++; if (i >= n) i = 0; O i = (i+1) % n;

Indipendentemente da ciò, sarei davvero sorpreso se questo è mai un problema significativo delle prestazioni.

4

I tested all 3 versions:

// plain wrap 
public static int WrapIndex(int index, int endIndex, int maxSize) 
{ 
    return (endIndex + index) > maxSize ? (endIndex + index) - maxSize : endIndex + index; 
} 

// wrap using mod 
public static int WrapIndexMod(int index, int endIndex, int maxSize) 
{ 
    return (endIndex + index) % maxSize; 
} 

// wrap by masking out the top bits 
public static int WrapIndexMask(int index, int endIndex, int maxSize) 
{ 
    return (endIndex + index) & (maxSize - 1); 
} 

I risultati di performance (zecche):

Plain: 25 Mod: 16 Mask: 16 (maxSize = 512) 
Plain: 25 Mod: 17 Mask: 17 (maxSize = 1024) 
Plain: 25 Mod: 17 Mask: 17 (maxSize = 4096) 

Così sembra che il modulo è la scelta migliore, in quanto non richiede alcuna restrizione alla dimensione della buffer.

11

migliore che è venuta in mente è:

public static int Wrap(int index, int n) 
{ 
    return ((index % n) + n) % n; 
} 

(Se c'è bisogno di lavorare con i numeri negativi)

+1

Non era ovvio per me quindi ecco un piccolo chiarimento: 'a' è l'indice che ha bisogno di essere spostato e' n' è la dimensione dell'array. – GER

Problemi correlati