std::ostringstream
As an old C programmer, I find itoa (or even sprintf!) most
convenient. However, here goes:
std::ostringstream oss;
int i = 123;
oss << i;
std::string s = oss.str();
http://www.boost.org/libs/conversion/lexical_cast.htm
int i = 10;
std::string s;
s = boost::lexical_cast<std::string>(i);
and works the other way round too
i = boost::lexical_cast<int>(s);
It will throw a boost::bad_lexical_cast exception if the conversion is
invalid.
Cheers
Russell
Although the standard method is highly portable, I still find that
using itoa is much faster. (even sprintf is faster than stringstream
convertion). So, If you love good performace, itoa will be a better
choice.
I tend to agree with you. However, the fact is that I have also
created innumerable bugs by using sprintf format values with the wrong
type of value. The function itoa() is not standard C or C++ and you
have to remember about _itoa or _ultoa or all the other versions. And
also "modern" programming tends to use all sorts of data items beyond
char, int, or float.
If you love good programming techniques, you will use the standard
methods. If you love good performance, then diligent attention to
your program design will yield far more effective results than relying
on a few little tricks.
>I tend to agree with you. However, the fact is that I have also
>created innumerable bugs by using sprintf format values with the wrong
>type of value. The function itoa() is not standard C or C++ and you
>have to remember about _itoa or _ultoa or all the other versions. And
>also "modern" programming tends to use all sorts of data items beyond
>char, int, or float.
>
>If you love good programming techniques, you will use the standard
>methods. If you love good performance, then diligent attention to
>your program design will yield far more effective results than relying
>on a few little tricks.
If you care about both portability and performance, you could write
your own itoa style function (perhaps less error prone and more
useful, e.g. with a stringLength reference argument that takes the
capacity of the buffer on the way in and gives the length of the
string on the way out).
Tom
You mean that the created function can have the higher portability
than the Standard method and the the higher performance than
the Implementation supportted method? Even less error prone and
more useful...
If so, I want to see the example. Would you...?
--
S Kim <st...@yujinrobot.com>
Here's one way...
#include <string>
#include <iostream>
std::string from_int(int i)
{
char digits[10]; // more than enough for int
int ix = sizeof(digits);
while (i)
{
digits[--ix] = i %10 + '0';
i /= 10;
}
if (ix == sizeof(digits))
digits[--ix] = '0';
return std::string(digits+ix,digits+sizeof(digits));
}
int main()
{
for (int i = 0; i < 20; ++i)
std::cout << i << ": " << from_int(i) << "\n";
}
Really?? But...
>
> Here's one way...
>
> #include <string>
> #include <iostream>
>
> std::string from_int(int i)
> {
> char digits[10]; // more than enough for int
Less portability for int type the limit 10 for large scale int type machine
and it causes Less performance for memory alignment in most 4 bytes
aligned machine.
> int ix = sizeof(digits);
> while (i)
> {
> digits[--ix] = i %10 + '0';
> i /= 10;
> }
> if (ix == sizeof(digits))
> digits[--ix] = '0';
> return std::string(digits+ix,digits+sizeof(digits));
> }
It only works for base 10 and positive number.
if from_int(-100), what is the result? Even it is error prone.
And your example is greatly slower than _itoa in my robust test.
May be it is not good example for tom's description.
--
S Kim <st...@yujinrobot.com>
>
> Less portability for int type the limit 10 for large scale int type
> machine and it causes Less performance for memory alignment in most 4
> bytes aligned machine.
I was too lazy to #include limits and size the array with an appropriate
calculation - it is just an example, afterall.
>
>> int ix = sizeof(digits);
>> while (i)
>> {
>> digits[--ix] = i %10 + '0';
>> i /= 10;
>> }
>> if (ix == sizeof(digits))
>> digits[--ix] = '0';
>> return std::string(digits+ix,digits+sizeof(digits));
>> }
>
> It only works for base 10
.. which is all that itoa works for as well.
> and positive number.
> if from_int(-100), what is the result? Even it is error prone.
... easily accomodated - it is just an example after all.
>
> And your example is greatly slower than _itoa in my robust test.
>
> May be it is not good example for tom's description.
Maybe not :)
Anything that returns std::string is going to be far slower than itoa just
from the time it takes to construct and copy a std::string, I'd imagine.
-cd
...I bet it's way faster than std::ostringstream though, and that was the
standard-conforming solution to which we're comparing. I'd imagine that
it's likely faster than sprintf too, but I wouldn't be too surprised if it's
close.
-cd
Ok. What is your target to compare?
There are many converting method on it like _itoa, itoa or using
std::ostringstream,or your constraint definition.
And now, how do you can calculate the size of arrary of char for
all implementations in the meaning of higher portability that it keeps
still higher performance than the Standard or your target Implementations.
Same problem airses in case of bases, and negative integer.
My point is this: Maximum portability can not stand with Maximum
Performance. Only constrainted implementations can be existed
in the extreamly limited mean such as your example.
There is no general answer to achieve that.
[snip]
--
S Kim <st...@yujinrobot.com>
#include <limits.h>
// GUARANTEED to be big enough
char digits[sizeof(int)*CHAR_BIT+1];
> Same problem airses in case of bases, and negative
> integer.
Different bases and negative numbers are minor additions.
> ... that it keeps
> still higher performance than the Standard or your target
> Implementations.
Who said it would be higher performance than implementation-specific
solutions? My only intent was to show something that's portable and more
efficient than std::ostringstream. My appologies for not responding to your
first post with "that's not possible".
> My point is this: Maximum portability can not stand with Maximum
> Performance. Only constrainted implementations can be existed
> in the extreamly limited mean such as your example.
> There is no general answer to achieve that.
Naturally. Maximum performance is nearly always implementation specific,
and I didn't see anyone offering a counter point.
Conversely, a highly portable implementation doesn't have to be slow.
-cd
You might be interested in looking at
http://www.cuj.com/documents/s=8006/cuj0212wilson/
http://www.cuj.com/documents/s=8840/cujexp0309wilson/
http://www.cuj.com/documents/s=8906/cujexp0311wilson/
http://www.cuj.com/documents/s=8943/cujexp0312wilson/
Matthew Wilson goes to great lengths to devise a fast way to convert
ints to strings. Four parts article on a seemingly trivial topic.
--
With best wishes,
Igor Tandetnik
"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken
My first indent is that. Higher performance than Implementation
specific and Higher Portability than Standard.
In my understanding, the tom's description seem to it.
May be it is leaded from misunderstanding caused on
my low quality of english. it's my second language. If so, My apology.
But, What is the "that's not possible"? I did not say it.
> Naturally. Maximum performance is nearly always implementation specific,
> and I didn't see anyone offering a counter point.
>
> Conversely, a highly portable implementation doesn't have to be slow.
Agree.
The highly portable needs not to be slow, but its first design rule is
the Portable not the Performance. And many highly portable
implementations are made by this principle.
And there are so many examples on it that
they have high portability but not high performance
than implementation specific cases on same (or reduced) solutions.
--
S Kim <st...@yujinrobot.com>
It's pretty easy to write a function (or overloaded function set) that
is:
1) Faster than the stringstream technique
2) Faster than sprintf
3) Portable (unlike _itoa)
4) Less error prone than itoa or sprintf
5) Works with different radices (up to 36)
6) Indicates failure via an exception (since failure of an itoa type
function is definitely exceptional)
Whether you'll beat the performance of itoa I don't know - I haven't
checked its source code (which may be assembler).
As with all problems, you have to trade genericity against safety and
ease of implementation; if you expose a version that works for output
iterators, you can end up writing off the end of an array, so I think
it's best to stick to containers (including the container-like
std::string), built in arrays, and pointers, with a specific buffer
size provided. The iterator version could be exposed if desired. Here
it is (messed around with to avoid VC7.1 warnings):
#include <limits>
#include <stdexcept>
#include <cstddef>
#include <algorithm>
#include <iterator>
namespace conv
{
namespace impl
{
template <typename IntT, class OutIt>
OutIt itoa(IntT i, OutIt it, std::size_t capacity, int
radix)
{
if (radix < 2 || radix > 36)
throw std::domain_error("itoa radix must be >=2 and
<=36");
IntT j = i < 0? static_cast<IntT>(0) - i : i;
char const* const digit_map =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::size_t const max_digits =
std::numeric_limits<IntT>::digits;
char buffer[max_digits];
char* ptr = buffer + sizeof buffer;
if (j == 0)
{
*--ptr = digit_map[0];
}
else
{
while (j)
{
*--ptr = digit_map[j%radix];
j /= radix;
}
}
std::size_t required_capacity = buffer + sizeof buffer -
ptr;
if (i < 0)
++required_capacity;
if (capacity < required_capacity)
throw std::runtime_error("itoa output buffer too
small");
if (i < 0)
*it = '-', ++it;
return std::copy(ptr, buffer + sizeof buffer, it);
}
}
template <typename IntT, class Cont>
inline void itoa(IntT i, Cont& container, int radix)
{
::conv::impl::itoa(i, std::back_inserter(container),
std::numeric_limits<std::size_t>::max(), radix);
}
template <typename IntT, std::size_t N>
inline void itoa(IntT i, char (&a)[N], int radix)
{
*::conv::impl::itoa(i, a, N - 1, radix) = '\0';
}
template <typename IntT, std::size_t N>
inline void itoa(IntT i, wchar_t (&a)[N], int radix)
{
*::conv::impl::itoa(i, a, N - 1, radix) = L'\0';
}
template <typename IntT>
inline void itoa(IntT i, char* a, std::size_t capacity, int
radix)
{
*::conv::impl::itoa(i, a, capacity - 1, radix) = '\0';
}
template <typename IntT>
inline void itoa(IntT i, wchar_t* a, std::size_t capacity, int
radix)
{
*::conv::impl::itoa(i, a, capacity - 1, radix) = L'\0';
}
}
#include <string>
#include <iostream>
int main()
{
long long l = -998766222734252301ll;
std::string s;
s.reserve(100);
conv::itoa(l, s, 10);
std::cout << s << '\n';
wchar_t a[10];
conv::itoa(27492, a, 16);
std::wcout << a << '\n';
try
{
wchar_t* ptr = a;
conv::itoa(97475809396ul, ptr, sizeof a, 2);
}
catch (std::exception const& e)
{
std::cout << e.what() << '\n';
}
}
I hope there aren't any bugs, and that performance is comparable to
_itoa.
Tom
<snip code which probably exhibits these characteristics>
I would bet that if you spent as much time analyzing and refining the
design of your program as you did in creating this example, you would
get far better performance out of your overall program. It is probably
a very rare and exceptional program in which converting int to string
is the major determinant of performance. Therefore pulling even an
inefficient package out of the standard library is probably the most
efficient and effective technique from the perspective of getting the
entire application done correctly.
><snip code which probably exhibits these characteristics>
>
>I would bet that if you spent as much time analyzing and refining the
>design of your program as you did in creating this example, you would
>get far better performance out of your overall program. It is probably
>a very rare and exceptional program in which converting int to string
>is the major determinant of performance. Therefore pulling even an
>inefficient package out of the standard library is probably the most
>efficient and effective technique from the perspective of getting the
>entire application done correctly.
When building library components for general consumption, you are not
targetting a specific program, and since you don't know the
performance requirements of the programs your library will be used
with, you have to assume the worst.
(e.g. Andrei Alexandrescu wrote:
"Often, a library writer doesn't know exactly how that library will be
used. The library might be used for mild tasks or in a speed-hungry
context. While a fast library can be used for mellow stuff, a slow
library can't be used in inner loops. My opinion in the matter is:
bottom line, a library writer's duty is to offer as good a set of
tradeoffs as possible.")
If you are writing an application and don't have conv::itoa (or
similar) available, you should of course use the standard library
functions until such time as profiling shows them to be too slow
(which will likely be never). At that point you go looking for a
faster solution, resorting to writing your own only if you can't find
an off the shelf solution.
Tom