anfängerprobleme mit sprintf
-
Ethon schrieb:
Oder einfach C-API. Da spart man sich den ganzen Streamoverhead (mind. 1 zusätzliche Allokation).
std::string to_hex_string(unsigned value) { char buffer[std::numeric_limits<unsigned>::digits]; return std::string(std::itoa(value, buffer, 16)); }
Nur, dass itoa kein Standard-C ist.
-
Tachyon schrieb:
Sorry, aber Hackers Lösung ist deutlich besser.
Mhm. Erklärst Du mir auch, warum?
-
Swordfish schrieb:
Tachyon schrieb:
Sorry, aber Hackers Lösung ist deutlich besser.
Mhm. Erklärst Du mir auch, warum?
Weil Deine Version sich sinnfreierweise so ziemlich alle Probleme einfängt, die static-Variablen so mit sich bringen. Was versprichst Du Dir davon? Ein Performancegewinn?
-
Tachyon schrieb:
Ethon schrieb:
Oder einfach C-API. Da spart man sich den ganzen Streamoverhead (mind. 1 zusätzliche Allokation).
std::string to_hex_string(unsigned value) { char buffer[std::numeric_limits<unsigned>::digits]; return std::string(std::itoa(value, buffer, 16)); }
Nur, dass itoa kein Standard-C ist.
Imho fast egal, da ich noch nie einen Compiler gesehen habe, der es nicht kann. Na dann einfach die Idee des OPs gefixt:
std::string to_hex_string(unsigned value) { char buffer[sizeof(value) * 2 + 1]; sprintf(buffer,"%x", value); return std::string(buffer); }
Immer noch schneller als per stringstream.
-
Tachyon schrieb:
Weil Deine Version sich sinnfreierweise so ziemlich alle Probleme einfängt, die static-Variablen so mit sich bringen.
Im konkreten Fall? Sorry, ich wills wirklich wissen.
Tachyon schrieb:
Was versprichst Du Dir davon? Ein Performancegewinn?
Ja, wenn ich auch nicht gemessen habe.
-
Swordfish schrieb:
Tachyon schrieb:
Weil Deine Version sich sinnfreierweise so ziemlich alle Probleme einfängt, die static-Variablen so mit sich bringen.
Im konkreten Fall? Sorry, ich wills wirklich wissen.
Was wenn bspw. Fehlerbits gesetzt werden?
-
Es ist auf jeden Fall nicht Threadsafe. Mit C++11 und thread_local könnte es Sinn machen, aber Variable reusing neigt oft dazu die Performance zu drücken, da der Compiler schlechter optimieren kann.
-
Swordfish schrieb:
Tachyon schrieb:
Weil Deine Version sich sinnfreierweise so ziemlich alle Probleme einfängt, die static-Variablen so mit sich bringen.
Im konkreten Fall? Sorry, ich wills wirklich wissen.
Ok, Threadsafe ist es (noch) nicht. Sonst?
Swordfish schrieb:
Tachyon schrieb:
Was versprichst Du Dir davon? Ein Performancegewinn?
Ja, wenn ich auch nicht gemessen habe.
Gemessen: // edit Fehlerbits noch löschen...
Swordfish: 591.937 Hacker: 1005.78 Ethon: 171.649
Gut, daß uns sprintf schlägt, ist klar...
#include <iostream> #include <sstream> #include <iomanip> #include <string> #include <cstdlib> #include <Windows.h> #define WIN32_LEAN_AND_MEAN std::string to_hex_string_swordfish( unsigned value ) { static std::ostringstream ss; ss.clear( ); ss.str( "" ); ss << std::hex << value; return ss.str( ); } std::string to_hex_string_hacker( unsigned value) { std::ostringstream stream; stream << std::hex << value; return stream.str(); } std::string to_hex_string_ethon(unsigned value) { char buffer[sizeof(value) * 2 + 1]; sprintf(buffer,"%x", value); return std::string(buffer); } int main( ) { HANDLE me = GetCurrentProcess( ); if( !SetPriorityClass( me, REALTIME_PRIORITY_CLASS ) ) { std::cerr << "SetPriorityClass failed!\n"; return EXIT_FAILURE; } std::srand( static_cast< unsigned >( std::time( 0 ) ) ); LARGE_INTEGER start, end; if( !QueryPerformanceFrequency( &start) ) { std::cerr << "QueryPerformanceFrequency failed!\n"; return EXIT_FAILURE; } double frequency = start.QuadPart / 1000.0; double elapsed; std::string result; // Swordfish QueryPerformanceCounter( &start ); for( size_t i = 0; i < 1000000; ++i ) { result = to_hex_string_swordfish( rand( ) ); } QueryPerformanceCounter( &end ); elapsed = ( end.QuadPart - start.QuadPart ) / frequency; std::cout << "Swordfish: " << elapsed << std::endl; // Hacker QueryPerformanceCounter( &start ); for( size_t i = 0; i < 1000000; ++i ) { result = to_hex_string_hacker( rand( ) ); } QueryPerformanceCounter( &end ); elapsed = ( end.QuadPart - start.QuadPart ) / frequency; std::cout << "Hacker: " << elapsed << std::endl; // Ethon QueryPerformanceCounter( &start ); for( size_t i = 0; i < 1000000; ++i ) { result = to_hex_string_ethon( rand( ) ); } QueryPerformanceCounter( &end ); elapsed = ( end.QuadPart - start.QuadPart ) / frequency; std::cout << "Ethon: " << elapsed << std::endl; }
-
Hat zwar nichts mit dem Thema zu tun... aber
#define WIN32_LEAN_AND_MEAN
nachdem du <windows.h> bereits eingebunden hast, scheint mir sinnlos zu sein.
-
Teste doch nochmal das hier:
template<typename CharT> std::basic_string<CharT> to_hex_string(unsigned value) { typedef std::basic_string<CharT> string_type; string_type result(sizeof(value) * 2, 0); typename string_type::reverse_iterator iter = result.rbegin(); while(value > 16) { unsigned cur = value % 16; *iter = cur < 10 ? CharT('0') + cur : CharT('A') + cur - 10; ++iter; value /= 16; } *iter = value < 10 ? CharT('0') + value : CharT('A') + value - 10; return result; }
-
camper schrieb:
Hat zwar nichts mit dem Thema zu tun... aber
#define WIN32_LEAN_AND_MEAN
nachdem du <windows.h> bereits eingebunden hast, scheint mir sinnlos zu sein.
Äh, ja
Ethon schrieb:
Teste doch nochmal das hier:
Ethon: 33.6387
-
Danke, wundert mich gerade etwas. Hat meine Implementierung irgendeine Macke? Denn std::to_string (C++11) schlage ich um mehr als das Doppelte.
So siehts jetzt aus:
template<typename CharT, int Base> std::basic_string<CharT> to_string(unsigned value) { CharT const lookup[] = { CharT('0'), CharT('1'), CharT('2'), CharT('3'), CharT('4'), CharT('5'), CharT('6'), CharT('7'), CharT('8'), CharT('9'), CharT('A'), CharT('B'), CharT('C'), CharT('D'), CharT('E'), CharT('F') }; typedef std::basic_string<CharT> string_type; string_type result(sizeof(value) * 2, 0); typename string_type::reverse_iterator iter = result.rbegin(); while(value > Base) { *iter = lookup[value % Base]; ++iter; value /= Base; } *iter = lookup[value]; return result; }
Kompilieren tu ich das Ganze mit dem GCC und -O3.
Edit: Ahhh, ich seh grad, wenn die Zahlen zu klein sind funktionierts nicht. Hmm ...
-
Tja, Ethon, du bist ein Genius.
-
Hacker schrieb:
Tja, Ethon, du bist ein Genius.
Lässt sich doch fixen. Bei 2x Speedup sollte das danach immer noch deutlich schneller sein. Mal ausprobieren.
-
Ethon schrieb:
Hacker schrieb:
Tja, Ethon, du bist ein Genius.
Lässt sich doch fixen. Bei 2x Speedup sollte das danach immer noch deutlich schneller sein. Mal ausprobieren.
Denkst du, dass, wenn du's an ISO/IEC schickst, sie es dann in den nächsten aufnehmen?
-
template<typename CharT, unsigned Base> std::basic_string<CharT> to_string(unsigned value) { static_assert(Base <= 16, "Unsupported Base"); CharT const lookup[] = { CharT('0'), CharT('1'), CharT('2'), CharT('3'), CharT('4'), CharT('5'), CharT('6'), CharT('7'), CharT('8'), CharT('9'), CharT('A'), CharT('B'), CharT('C'), CharT('D'), CharT('E'), CharT('F') }; std::array<CharT, std::numeric_limits<unsigned>::digits> buffer; auto iter = buffer.rbegin(); while(value > Base) { *iter = lookup[value % Base]; ++iter; value /= Base; } *iter = lookup[value]; return std::basic_string<CharT>(&(*iter), buffer.end()); }
Gefixt und noch schneller geworden.
Zum Konvertieren von 10.000.000 rand Werten braucht meine Funktion
real 0m11.909s
user 0m11.905s
sys 0m0.000sund std::to_string
real 0m26.853s
user 0m26.838s
sys 0m0.004sAlso, was ist der Unterschied?
-
Ethon!! Welchen Compiler benutzt du? Alter, mein GCC 4.7 meckert, dass to_string nicht deklariert ist (obwohl ich string implementiere). Was soll ich nur tun :schluchz:
-
Gcc 4.6.1
Kompiliert mit:
g++ -o test -O3 -march=native -std=c++0x test.cpp
Für std::to_string brauchst du <string> und den C++11 Switch.
-
Ethon schrieb:
Gcc 4.6.1
Kompiliert mit:
g++ -o test -O3 -march=native -std=c++0x test.cpp
Für std::to_string brauchst du <string> und den C++11 Switch.
Funktioniert immer noch nicht.
-
Ethon schrieb:
return std::basic_string<CharT>(&(*iter), buffer.end());
Bist Du sicher, daß basic_string diesen c-tor haben muss?