예전 회사에 다닐때 VBA를 사용했었는데 책도 없고 인터넷도 사용할 수 없고 VBA도 잘 모르는 상황에서
급하게 숫자를 문자열로 만드는 로직이 필요해서 구현했었고
그 후로 이직중에 면접 문제로 비슷한 문제가 나와서 화이트 보드에 C언어로 구현해 본적이 있었다.
그러다 작년쯤에 심심해서 다음과 같이 해당 로직 그대로 C++ 템플릿으로 작성해 보았다.
inline char IntToChar( int num )
{
switch ( num )
{
case 0: return '0';
case 1: return '1';
case 2: return '2';
case 3: return '3';
case 4: return '4';
case 5: return '5';
case 6: return '6';
case 7: return '7';
case 8: return '8';
case 9: return '9';
default:
{
//assert( true ); // num is not 0 to 9
}
break;
}
return '0';
}
inline wchar_t IntToWChar( int num )
{
switch ( num )
{
case 0: return L'0';
case 1: return L'1';
case 2: return L'2';
case 3: return L'3';
case 4: return L'4';
case 5: return L'5';
case 6: return L'6';
case 7: return L'7';
case 8: return L'8';
case 9: return L'9';
default:
{
//assert( true ); // num is not 0 to 9
}
break;
}
return L'0';
}
// ToString
template < typename T >
inline std::string ToString( T input );
template <>
inline std::string ToString( std::string input )
{
return input;
}
template <>
inline std::string ToString( unsigned __int64 input )
{
std::string result;
do
{
result = IntToChar( input % 10ULL ) + result;
input /= 10ULL;
} while ( input != 0ULL );
return result;
}
template <>
inline std::string ToString( __int64 input )
{
bool isMinus = ( input < 0LL );
if ( isMinus )
{
input *= -1LL;
}
return ( isMinus ? "-" : "" ) + ToString< unsigned __int64 >( input );
}
//template <>
//inline std::string ToString( double input )
//{
// bool isMinus = ( input < 0. );
// if ( isMinus )
// {
// input *= -1.;
// }
// return ( isMinus ? "-" : "" ) + ToString< unsigned __int64 >( input );
//}
template < typename T >
inline std::string ToString( T input )
{
return ToString< __int64 >( static_cast<__int64>( input ) );
}
// ToString End
// ToWString
template < typename T >
inline std::wstring ToWString( T input );
template <>
inline std::wstring ToWString( std::wstring input )
{
return input;
}
template <>
inline std::wstring ToWString( unsigned __int64 input )
{
std::wstring result;
do
{
result = IntToWChar( input % 10ULL ) + result;
input /= 10ULL;
} while ( input != 0ULL );
return result;
}
template <>
inline std::wstring ToWString( __int64 input )
{
std::wstring result;
bool isMinus = ( input < 0LL );
if ( isMinus )
{
input *= -1LL;
}
return ( isMinus ? L"-" : L"" ) + ToWString< unsigned __int64 >( input );
}
template < typename T >
inline std::wstring ToWString( T input )
{
return ToWString< __int64 >( input );
}
// ToWString End
물론 sprintf 방식으로 만들수 있다는 것도 알고는 있지만 이 방식으로 얼마나 빠를지가 궁금 했었고
나중에 sprintf 방식으로도 만들어서 속도를 비교 해보려고 했었다.
이제 float과 double도 작성해야지 하고 있던 참에 std::to_string(), std::to_wstring() 을 발견하였다.
MSVS2013 기준으로 정수형은 모두 sprintf 로 구현되어 있었고 float, double, long double 도 구현되어 있었다.
그런 이유로 바로 속도 테스트 시작!
ToString Test Result
std result = count : 100, Total seconds : 0.000645, Average seconds : 0.000006, range : -9 ~ 9
std result = count : 100, Total seconds : 0.003895, Average seconds : 0.000039, range : -99 ~ 99
std result = count : 100, Total seconds : 0.043744, Average seconds : 0.000437, range : -999 ~ 999
std result = count : 100, Total seconds : 0.507521, Average seconds : 0.005075, range : -9999 ~ 9999
std result = count : 100, Total seconds : 5.388189, Average seconds : 0.053882, range : -99999 ~ 99999
std result = count : 100, Total seconds : 58.495743, Average seconds : 0.584957, range : -999999 ~ 999999
std result = count : 100, Total seconds : 648.189087, Average seconds : 6.481891, range : -9999999 ~ 9999999
std result = count : 100, Total seconds : 7002.231934, Average seconds : 70.022316, range : -99999999 ~ 99999999
std result = count : 100, Total seconds : 68199.750000, Average seconds : 681.997498, range : -999999999 ~ 999999999
Gum result = count : 100, Total seconds : 0.000341, Average seconds : 0.000003, range : -9 ~ 9
Gum result = count : 100, Total seconds : 0.002807, Average seconds : 0.000028, range : -99 ~ 99
Gum result = count : 100, Total seconds : 0.037484, Average seconds : 0.000375, range : -999 ~ 999
Gum result = count : 100, Total seconds : 0.503361, Average seconds : 0.005034, range : -9999 ~ 9999
Gum result = count : 100, Total seconds : 6.752371, Average seconds : 0.067524, range : -99999 ~ 99999
Gum result = count : 100, Total seconds : 79.450287, Average seconds : 0.794503, range : -999999 ~ 999999
Gum result = count : 100, Total seconds : 906.220520, Average seconds : 9.062205, range : -9999999 ~ 9999999
Gum result = count : 100, Total seconds : 10006.326172, Average seconds : 100.063263, range : -99999999 ~ 99999999
Gum result = count : 100, Total seconds : 102759.484375, Average seconds : 1027.594849, range : -999999999 ~ 999999999
( 각 마지막 9자리의 경우는 테스트 중에 컴퓨터를 사용했기 때문에 정확하지 않을 수 있다. )
1~3자리의 숫자는 내가 구현한 쪽이 빠르지만 4자리가 넘어가면 std::to_string() 이 더 빠르다.
( 자리수 별로 돌린게 아닌 숫자 범위로 돌렸기 때문에 -9999~9999 에 -999~999가 포함되어있다. )