Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

converstion of int to string

Status
Not open for further replies.

Haunter

Programmer
Jan 2, 2001
379
US
I am using the above code inside a template to convert basically any basic type to a string. More to the point float, double and int are being converted to strings
template<class num>
string intToStrig( num )
{
ostringstream stream;
stream<< num << flush;
string str(stream.str());
return str;

}

I am wondering if this is efficient and fast. Is there a better way to do the conversion? This conversion is done constantly and I need it to be a high speed low overhead conversion.

Thanks for your comments


haunter@battlestrata.com
 
Well, you may return stream.str() without auxiliary string str.
An alternative method is:
Code:
inline string toStr4(double x) // may be w/o inline
{
  char buff[32];
  sprintf(buff,"%g",x);
  return buff;
} // and so on for int, long etc
It seems the 2nd method is faster than ostrstream variant (1.5-2 times faster on VC++ (P4), but it depends on your processor and compiler).
It's funny but (not portable) direct conversion routine _gcvt() (double to C-string) is NOT faster than sprintf()...
In many cases old good C-library members still are the best choice...
 
Thanks!

Do you know where I could get some code to help benchmark code snippets?


haunter@battlestrata.com
 
Sorry, I don't know Unix-bases profilers...
You can get a rough estimation with (portable) clock() function. Select code fragment then call it in a loop 1000-10000 times:
Code:
#include <ctime>
const int n = 1000;
clock_t t0, t;
t0 = clock();
for (int i = 0; i < n; ++i)
{
// tested code (function call, for example)
}
t = clock() - t; // time in ticks (see clock() specs).
In many (practical;) cases it's enough.
Be careful: you can't estimate too fast code fragments with this method. Switch off high level optimization (tested code may go out of the loop body).
 
Boost ( has something similar called lexical_cast. The difference is that lexical_cast will let you convert anything to anything as long as they have a compatible string representation.

It's implemented in the style of a C++ cast.

e.g.
Code:
Foo f = lexical_cast<Foo>(bar);

This will likely actually be in the C++ Standard within the next few years, too.


For a quick profile, if you're using bash, try using the "time" builtin.
 
Code:
  char buff[32];
  sprintf(buff,"%g",x);
  return buff;
Ugh, returning a pointer to a local variable - very bad.

> I am wondering if this is efficient and fast.
Compared to how slow actually reading information from a hard disk is likely to be, the performance of a int-to-string say is probably inconsequential.

When your program is finished, and you have some actual real-world data to test with, then you can use a profiler.

--
 
If you have MS Visual C++ you might want to look at the source code for the itoa() function. It would appear to me to be the fastest way to convert integers to strings.
I just copied their code and cleaned it up a bit and conveted it into a template for my own use... ;)
 
itoa isn't portable though, unless you use condition includes to use something else on other systems.

The problem will always be o(n) in the number of digits in the number... Streams and sprintf have a lot of overhead, I'd write it:
Code:
string itoa(int i)
{
  int rem = 0;
  string ret;
  while(0 < i)
  {
    rem = i%10;
    i = i/10;
    ret += (char)(rem + '0');
  }
  return ret;
}
 
Salem,
see returned value type: std::string. This bad local pointer will be casted into a string object!...
 
jstreich : "Streams and sprintf have a lot of overhead, I'd write it..."

Apart from its obvious faults (it doesn't work for i < 0 and generates a reversed string) string concatenations impose quite an overhead as well.

Don't underestimate the power of sprintf ;-)

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Following the paradigm of Reinventing The Wheel Just For Fun, RTWJFF(tm), I'd implement it somewhat like this:

Code:
const char* itoaChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

std::string my_itoa(int i, unsigned int radix)
{
  if(i==0)
  {
    return "0";
  }
  else
  {
    const int cBuffSize = 32;
    char buff[cBuffSize];

    bool neg = i<0;
    if (neg)
    {
      i= -i;
    }

    // Set chars from the end of the buffer
    char* ptr = &buff[cBuffSize-1];
    *ptr = 0;
    while(i)
    {
      ptr--;
      *ptr =  itoaChars[i%radix];
      i = i/radix;
    }
    if (neg)
    {
      ptr--;
      *ptr = '-';
    }

    // Return ptr to first char thats's set in the buffer
    return ptr;
  }
}

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
So you're saying this isn't portable?? Why not?
Code:
template <class TNumType>
static TNumType
abs( TNumType  num )
{
	if ( num < 0 )
	{
		return -1 * num;
	}

	return num;
}

template <class TNumType>
static bool
xtoa(	  TNumType  num,
	  std::string&  strNum,
	  unsigned int  uiBase,
			  bool  bIsNeg )
{
	// 10 numbers + 26 letters = 36.  I don't know what else to use for bases
	// higher than 36?  Also, can't divide by 0...
	if ( (uiBase == 0) || (uiBase > 36) )
	{
		return false;
	}

	char cDigit;				// Temp char.
	unsigned int uiDigitVal;	// Value of digit.
	strNum.erase();

	if ( bIsNeg == true )
	{
		num = abs( num );	// Make it positive.
	}

	do
	{
		uiDigitVal = (num % uiBase);
		num /= uiBase;		// Get next digit.

		// Convert to ascii and store.
		if (uiDigitVal > 9)
		{
			cDigit = static_cast<char>( uiDigitVal - 10 + 'A' );	// A letter.
		}
		else
		{
			cDigit = static_cast<char>( uiDigitVal + '0' );			// A digit.
		}

		strNum += cDigit;
	} while ( num > 0 );

	// We now have the digits of the number in the buffer, but in reverse
	// order.  So we need to reverse them now.

	std::reverse( strNum.begin(), strNum.end() );

	if ( bIsNeg == true )
	{
		strNum.insert( 0, "-" );
	}

	return true;
}

std::string&
itoa(		   int  iNum,
	  std::string&  strNum,
			   int  uiBase ) throw (std::exception)
{
	bool bIsNeg = (iNum < 0 );

	if ( xtoa( iNum, strNum, uiBase, bIsNeg ) == false )
	{
		throw std::exception();
	}

	return strNum;
}
 
0 < i wasn't the problem, the ret += was, I was appending to the end instead f the begining.... This works:
Code:
string itoa(int i)
{
  int rem = 0;
  string ret;
  while(0 < i)
  {
    rem = i%10;
    i = i/10;
    ret = (char)(rem + '0') + ret;
  }
  return ret;
}
 
>0 < i wasn't the problem

No, but i < 0 is.



/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Ah, yes... ummm... mine was the unsigned version... ;p

Star for catching it and putting my ego bacck into place.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top