Fast Numerical Formatting

.

Environment: VC6 SP4, W2k SP2

Display of the most financial data is required to be formated with a thousand separator. Like: 1000000 to be formated and displayed as "1,000,000"

There are lots of ways to do this formating, but there is no default crt function to do this for you. Here I try to present 2 functions, with very good performance that can be used for this this type of formating. Here is the most simple implementation.

static char sDecimalSeparator = '.'; // dot by default
static char sThousantSeparator =','; // comma by default

// call this to format a long to a string
static char* __stdcall long2str( char* szBuffer, long lValue )
{
  char *p;                // pointer to traverse string
  char *firstdig;         // pointer to first digit
  char temp;              // temp char
  unsigned digval;        // value of digit
  unsigned long val;

  p = szBuffer;

  if (lValue < 0 ) {
      // negative, so output '-' and negate
     *p++ = '-';
     val = (unsigned long)(-(long)lValue); // make it positive!!
  } else
     val = lValue;

  firstdig = p;    // save pointer to first digit

  int iDecimalPos = 0;

  do {
     iDecimalPos ++;
     if (iDecimalPos != 4)
     {
       digval = (unsigned) (val % 10);
       val /= 10;                     // get next digit
       *p++ = (char) (digval + '0');  // and store the digit
     } else
     {
       *p++ = sThousantSeparator;
       iDecimalPos = 0;
     }
  } while (val > 0);

  //  We now have the digit of the number in the buffer, 
  // but in reverse order.  Thus we reverse them now.

  *p-- = '\0';    // terminate string; p points to last digit

  do {
      temp = *p;
      *p = *firstdig;
      *firstdig = temp;   // swap *p and *firstdig
      --p;
      ++firstdig;         
  } while (firstdig < p); // repeat until halfway

  return szBuffer;
}

Now, most of the financial data is displayed with a sign as a number trailer.
eg: 1000+ or 1000-
Here is a new implementation one with this new functionality: adding the sign after the number, regarding it's positive or negative.

static char sDecimalSeparator = '.'; // dot by default
static char sThousantSeparator =','; // comma by default

// call this to format a long to a string
// iShowSign = 0 - show only the default "-" sign
// iShowSign = 1 - show minus/plus signs always at the 
//                 begining of the number (eg: +1000, -1000)
// iShowSign = 2 - show minus/plus signs always at the 
//                 end of the number (eg: 1000+, 1000-)
static char* __stdcall long2str( char* szBuffer,
                                 long lValue,
                                 int iShowSign = 0 )
{
  char *p;               // pointer to traverse string
  char *firstdig;        // pointer to first digit
  char temp;             // temp char
  unsigned digval;       // value of digit
  unsigned long val;

  p = szBuffer;

  if (lValue < 0 ) {
     // negative, so output '-' and negate
     if (iShowSign < 2)
       	*p++ = '-';
     val = (unsigned long)(-(long)lValue); // make it positive!!
  } else
  {
     if  ( iShowSign == 1 )
       *p++ = '+';
     val = lValue;
  }

  firstdig = p;     // save pointer to first digit

  int iDecimalPos = 0;

  do {
     iDecimalPos ++;
     if (iDecimalPos != 4)
     {
       digval = (unsigned) (val % 10);
       val /= 10;                    // get next digit
       *p++ = (char) (digval + '0'); // and store the digit
     } else
     {
       *p++ = sThousantSeparator;
       iDecimalPos = 0;
     }
  } while (val > 0);

  //  We now have the digit of the number in the buffer, 
  // but in reverse order.  Thus we reverse them now.

  // Check if we have to add signs
  if ( iShowSign == 2 )
  {
     if ( lValue < 0 )
       *p++ = '-';
     else
       *p++ = '+';
     *p-- = '\0'; // terminate string; p points to last digit
     *p--; // go back one more step to leave the sign sign intact!
  } else
  {
     *p-- = '\0'; // terminate string; p points to last digit
  }

  do {
      temp = *p;
      *p = *firstdig;
      *firstdig = temp;   // swap *p and *firstdig
      --p;
      ++firstdig;
  } while (firstdig < p); // repeat until halfway

  return szBuffer;
}

I hope that this is as useful to you, as it would have been for me some time ago. If you have implementations that are faster than those two, please send them to me.