Interesting Performance of snprintf() on Linux

Speed

I was trying to speed up the conversion of floating point numbers to integers today, and I came across some really interesting data. My initial code was very straight forward: I'd multiply the double by 1000, make it an integer, snprintf() it, and then look at the last character to see if it's a '0' - if it is, I remove it, if not, I keep it. Then I place the decimal point where I know it needs to be.

The code is simple, and not very creative at all:

  char      buff[16];
  bzero(buff, 16);
  snprintf(buff, 15, "%d", (uint32_t)(value * 1000));
  size_t  len = strlen(buff);
  size_t  lm1 = len - 1;
  size_t  lm2 = len - 2;
  size_t  lm3 = len - 3;
  if (buff[len] != '0') {
    buff[len] = buff[lm1];
  }
  buff[lm1] = buff[lm2];
  buff[lm2] = buff[lm3];
  buff[lm3] = '.';

This runs, and while it's not perfect, it's pretty fast. It's certainly faster because I precompute the index values, but that's just smart work. What I found was that using pointers and not doing the references really isn't any faster than using the references.

Then I looked up fast C++ integer to string and saw what a was out there. One guy wrote about this amazingly fast system he had written, so I gave it a look. What was interesting to me was the second place in the speed race was won by an STL string method that built up the number in reverse order by dividing by 10 and then doing a modulo on each digit, and finally reversing it.

So I tried it.

Not even close to the snprintf() version I had.

His results could have been for an older version of the compiler, or something, but I didn't see snprintf() as slow -- in fact, it was faster than anything else I tried. Amazing.

You just have to trust the compiler, and the OS. It'll get you there most of the time.