Link to home
Start Free TrialLog in
Avatar of Exceter
ExceterFlag for United States of America

asked on

printf() radix conversions

What algorithm does printf use to convert integers to radix 16? printf must evaluate its input string, find the variable in its va_list, convert it into hex, and format it somewhere along the way. I would have thought that I could write my own conversion that would be faster as I don't need the format string and the va stuff. However, I keep finding that printf outperforms my algorithms by roughly .2 seconds when outputing 9000+ shorts. What is printf doing? Is it possible that the compiler's author(s) used asm code to get the speed or am I missing something?

Exceter
Avatar of MrNed
MrNed
Flag of Australia image

Such a common function would be optimised to the hilt. Its most likely written in asm. But the conversion isnt the only thing that can cause the 200ms difference - theres function calling overhead aswell. What does your code look like?
Avatar of Ajar
Ajar

such library functions are  optimized by the compiler not only by the asm implementation but also by
using the special facilities provided by a particular cpu hardware architecture .

> What is printf doing?

Assuming you really mean "How is it doing it?", that depends on your particular library implementation.  It's impossible to answer for all library implementations in general.  It may be possible to trace into the disassembly of the printf function to see how it formats hexadecimal strings.  If you specify what compiler you are using, some wizardly expert here may be able to give you a specific answer.

> Is it possible that the compiler's author(s) used asm code to get the speed or am I missing something?

Both are quite possible.  ;-)

--efn
I tried a half dozen different ways to implement it.  With compiler optimization -O3,
this was the most efficient implementation:

static inline char * tohex32c(char * buff, unsigned int n)
{
  static char hexd[] = "0123456789ABCDEF";
  if (buff) {
    *buff++ = hexd[ (n >> 28) & 15 ];
    *buff++ = hexd[ (n >> 24) & 15 ];
    *buff++ = hexd[ (n >> 20) & 15 ];
    *buff++ = hexd[ (n >> 16) & 15 ];
    *buff++ = hexd[ (n >> 12) & 15 ];
    *buff++ = hexd[ (n >> 8) & 15 ];
    *buff++ = hexd[ (n >> 4) & 15 ];
    *buff++ = hexd[ n & 15 ];
    *buff = '\0';
  }
  return buff;
}

With no optimization, this macro version was faster:

static inline char * tohex32c(char * buff, unsigned int n)
{
  static char hexd[] = "0123456789ABCDEF";
  if (buff) {
    *buff++ = hexd[ (n >> 28) & 15 ];
    *buff++ = hexd[ (n >> 24) & 15 ];
    *buff++ = hexd[ (n >> 20) & 15 ];
    *buff++ = hexd[ (n >> 16) & 15 ];
    *buff++ = hexd[ (n >> 12) & 15 ];
    *buff++ = hexd[ (n >> 8) & 15 ];
    *buff++ = hexd[ (n >> 4) & 15 ];
    *buff++ = hexd[ n & 15 ];
    *buff = '\0';
  }
  return buff;
}

Avatar of Kent Olsen

Hi Brett,

Depending upon the underlying instruction set, picking a character from within a string could be fairly expensive.  Can you retry your tests with the array defined as:

static int hexd[16] =
{
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};


Thanks,
Kent
ASKER CERTIFIED SOLUTION
Avatar of brettmjohnson
brettmjohnson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

Wow!  That is a surprise.  I would have expected at least comparable execution times due to caching.

The things you learn just by showing up.   :)


Thanks Brett,
Kent