I put together some tests here, and here is what I came up with:
write_ushort: 7.81 s
uShortToStr: 8.16 s
translation: 6.71 s
use_sprintf: 49.66 s
(Write_ushort is my version, which I tried to write as clearly as possible, and not micro-optimize, for formatting to a given character buffer; use_sprintf is the obvious sprintf (buf, "% d", x) and nothing else, the other two taken from other answers here.)
This is a pretty amazing difference between the two, right? Who would have thought to use sprintf when faced with almost different sizes? Oh yes, how many times have I repeated each function tested?
// 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];
Sprintf turned the entire possible range of unsigned shorts, and then the entire range again increased by 2999 times by about 0.25 Ξs per average conversion on my laptop with a 5-year year.
Sprintf is portable; Is it also effective enough for your requirements?
My version:
// 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; }
The compilation functions of the TMP protocol are not new, but include this complete example, because this is what I used:
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 }; };