L'operazione può essere eseguita in (veloce) tempo costante su qualsiasi architettura che abbia zeri iniziali del conteggio o istruzioni simili (che è la maggior parte delle architetture). Ecco un frammento C ho seduti intorno per calcolare il numero di cifre in base dieci, che è essenzialmente lo stesso compito (assume una gcc come compilatore e 32 bit int):
unsigned int baseTwoDigits(unsigned int x) {
return x ? 32 - __builtin_clz(x) : 0;
}
unsigned int tenToThe[] = {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
};
unsigned int baseTenDigits(unsigned int x) {
unsigned int guess[33] = {
0, 0, 0, 0, 1, 1, 1, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 5, 5, 5,
6, 6, 6, 6, 7, 7, 7, 8, 8, 8,
9, 9, 9
};
unsigned int digits = guess[baseTwoDigits(x)];
return digits + (x >= tenToThe[digits]);
}
GCC e clang compilare questo fino a ~ 10 istruzioni su x86. Con cura, è possibile renderlo più veloce ancora in fase di montaggio.
L'intuizione chiave consiste nell'utilizzare il logaritmo di base-due (estremamente economico) per ottenere una stima rapida del logaritmo di base-dieci; a quel punto abbiamo solo bisogno di confrontarci con una singola potenza di dieci per decidere se dobbiamo aggiustare l'ipotesi. Questo è molto più efficiente della ricerca attraverso più poteri di dieci per trovare quello giusto.
Se gli ingressi sono in modo preponderante polarizzato su numeri a una e due cifre, una scansione lineare a volte è più veloce; per tutte le altre distribuzioni di input, questa implementazione tende a vincere abbastanza facilmente.
Hai bisogno di qualcosa che sia veloce, ma non ottimizzato, in nessuna lingua particolare. Buona fortuna. –
Che lingua stai usando? –
@Scott Hunter mi dispiace non averlo spiegato più chiaramente. Intendevo l'ottimizzazione del compilatore. Sono principalmente interessato al concetto di una funzione di registro efficiente che restituisce int. – laurisvr