ho messo insieme una prova di varie funzioni qui, e questo è ciò che mi si avvicinò con:
write_ushort: 7.81 s
uShortToStr: 8.16 s
convert : 6,71 s
use_sprintf: 49,66 s
(Write_ushort è la mia versione, che ho provato a scrivere chiaramente come p ossibile, piuttosto che micro-ottimizzare, da formattare in un determinato buffer di caratteri; use_sprintf è l'ovvio sprintf (buf, "% d", x) e nient'altro; gli altri due sono presi da altre risposte qui.)
Questa è una differenza piuttosto sorprendente tra loro, non è vero? Chi avrebbe mai pensato di usare lo sprint con una differenza di quasi un ordine di grandezza? Oh, sì, quante volte ho ripetuto ogni funzione testata?
// Taken directly from my hacked up test, but should be clear.
// Compiled with gcc 4.4.3 and -O2. This test is interesting, but not authoritative.
int main() {
using namespace std;
char buf[100];
#define G2(NAME,STMT) \
{ \
clock_t begin = clock(); \
for (int count = 0; count < 3000; ++count) { \
for (unsigned x = 0; x <= USHRT_MAX; ++x) { \
NAME(x, buf, sizeof buf); \
} \
} \
clock_t end = clock(); \
STMT \
}
#define G(NAME) G2(NAME,) G2(NAME,cout << #NAME ": " << double(end - begin)/CLOCKS_PER_SEC << " s\n";)
G(write_ushort)
G(uShortToStr)
G(convert)
G(use_sprintf)
#undef G
#undef G2
return 0;
}
sprintf convertito l'tutta la gamma possibile di pantaloncini firmati, poi ha fatto ancora una volta l'intera gamma 2.999 volte più a circa 0,25 microsecondo per la conversione, in media, sul mio ~ 5 anni portatile.
Sprintf è portatile; è anche abbastanza efficiente per le tue esigenze?
La mia versione:
// Returns number of non-null bytes written, or would be written.
// If ret is null, does not write anything; otherwise retlen is the length of
// ret, and must include space for the number plus a terminating null.
int write_ushort(unsigned short x, char *ret, int retlen) {
assert(!ret || retlen >= 1);
char s[uint_width_10<USHRT_MAX>::value]; // easy implementation agnosticism
char *n = s;
if (x == 0) {
*n++ = '0';
}
else while (x != 0) {
*n++ = '0' + x % 10;
x /= 10;
}
int const digits = n - s;
if (ret) {
// not needed by checking retlen and only writing to available space
//assert(retlen >= digits + 1);
while (--retlen && n != s) {
*ret++ = *--n;
}
*ret = '\0';
}
return digits;
}
fase di compilazione log funzioni TMP non sono una novità, ma tra cui questo esempio completo, perché è quello che ho usato:
template<unsigned N>
struct uint_width_10_nonzero {
enum { value = uint_width_10_nonzero<N/10>::value + 1 };
};
template<>
struct uint_width_10_nonzero<0> {
enum { value = 0 };
};
template<unsigned N>
struct uint_width_10 {
enum { value = uint_width_10_nonzero<N>::value };
};
template<>
struct uint_width_10<0> {
enum { value = 1 };
};
Hai provato a usare ' sprintf'/'snprintf'? Fatto ciò, hai profilato il codice e stabilito che si tratta di un hotspot di prestazioni? –
Le tabelle nella parte inferiore dell'articolo collegato sotto illustrano chiaramente dove si trovano le implementazioni di stdlib per quanto riguarda l'efficienza e l'ottimalità di implementazione: http://www.codeproject.com/KB/recipes/Tokenizer.aspx –