Sto provando a scrivere una funzione senza ramo per restituire il MAX o il MIN di due numeri interi senza ricorrere a if (o? :). Utilizzando the usual technique posso farlo abbastanza facilmente per una data dimensione parola:Funzione branchless int max/min templatizzata
inline int32 imax(int32 a, int32 b)
{
// signed for arithmetic shift
int32 mask = a - b;
// mask < 0 means MSB is 1.
return a + ((b - a) & (mask >> 31));
}
Ora, supponendo arguendo che mi sto scrivendo il tipo di applicazione sul tipo di processore in-ordine dove ciò sia necessario, la mia domanda è se esiste un modo per utilizzare i modelli C++ per generalizzare questo a tutte le dimensioni di int.
Il passo >> 31 funziona solo per int32s, naturalmente, e mentre ho potuto copiare fuori sovraccarichi sulla funzione per int8, Int16, Int64 e, sembra che devo usare una funzione template, invece. Ma come ottengo la dimensione di un argomento modello in bit?
C'è un modo migliore per farlo rispetto a questo? Posso forzare la firma della maschera T? Se T non è firmato, il passaggio di spostamento della maschera non funzionerà (perché sarà uno spostamento logico piuttosto che aritmetico).
template< typename T >
inline T imax(T a, T b)
{
// how can I force this T to be signed?
T mask = a - b;
// I hope the compiler turns the math below into an immediate constant!
mask = mask >> ((sizeof(T) * 8) - 1);
return a + ((b - a) & mask);
}
E, dopo aver fatto quanto sopra, posso impedire che venga utilizzato per qualsiasi cosa, ma un tipo intero (ad esempio, nessun galleggianti o classi)?
maggior parte delle macchine moderne hanno istruzioni mov Conditonal, che consentono loro di fare min/max senza rami (ad es., Cmp a, b/movlt a, b). Questo sarebbe più veloce del codice che si intende generare e i compilatori ne sono a conoscenza. Sei sicuro che il tuo compilatore non lo faccia già per te? –
@IraBaxter Assolutamente sicuro; Guardo sempre la sua assemblea. Inoltre, il target del processore I (derivato da un PowerPC) non ha sicuramente un cmov. – Crashworks
Qualunque sia il codice che scrivi, sarà senza ramo solo come sorgente C++. Il compilatore può generare salti condizionali (cioè rami) senza scrivere se/else /? /:, E viceversa può generare istruzioni branchless ottimizzate dalla fonte if/else. – galinette