Länge eines stringstreams, wie?



  • theliquidwave schrieb:

    @ volkard:
    -200 * -1 = 200 = abs(-200)
    Mit Minuszahlen entsteht sonst eine Endlosschleife...
    Gruß

    Ein Bißchen mehr Begründung hatte ich mir erträumt, denn bei mir gibt

    int i=-200;
    	cout<<i<<' '<<get_length(i)<<'\n';
    

    brav

    -200 4
    

    aus.



  • wenn das minus in der länge mitzählen soll müsste die fkt so aussehen:

    int get_length(int value, bool count_minus = false)
    {
      int ret_val = count_minus && value < 0;
      for(; value != 0; ++ret_val)
        value /= 10;
      return ret_val;
    }
    

    bb



  • unskilled schrieb:

    wenn das minus in der länge mitzählen soll müsste die fkt so aussehen:

    int get_length(int value, bool count_minus = false)
    {
      int ret_val = count_minus && value < 0;
      for(; value != 0; ++ret_val)
        value /= 10;
      return ret_val;
    }
    

    bb

    Da wäre ich bei der 0 noch anderer Meinung.
    Deswegen bevorzuge ich do

    int get_length(int value, bool count_minus = false)
    {
      int ret_val = count_minus && value < 0;
      do
        ++ret_val;
      while(value /= 10);
      return ret_val;
    }
    


  • hmm... ich find do-while hässlich 😛
    war aber auch die ganze zeit davon ausgegangen, dass 0 die länge null haben sollte... mein fail : D

    int get_length(int value, bool count_minus = false)
    {
      int ret_val( value == 0 || count_minus && value < 0 );
      for(; value != 0; ++ret_val)
        value /= 10;
      return ret_val;
    }
    

    kein plan, ob das performance-mäßig was bringt, ich denke zwar schon, aber bin zu faul zu vergleichen... ^^

    bb



  • Hi,
    könnte man das Problem nicht einfacher lösen?
    Soweit ich mich erinnere kann man mit dem Logarithmus die Anzahl der stellen ermitteln...
    Man nehme entsprechend zum Zahlensystem einen Logarithmus und Rundet auf...
    Für das Dezimalsystem :

    int getLenght(int const& X)
    {
        return log10( abs(X) ) +1 + (X<0);
    }
    

    Gruss

    Edit:
    Man müsste noch testen bis zu welcher Zahl es sich lohnt, die schleifenversion zu nehmen und danach zu prüfen.



  • ich glaube kaum, dass es sich bei einer 32bit zahl überhaupt lohnen wird...

    alleine schon die ständigen umwandlungen wären für mich schon grund genug, es nicht zu verwenden...

    int g0(int const& X)
    {
        return log10( abs(X) ) +1 + (X<0);
    }
    

    kompiliert bei mir nicht mal (msvc9):
    error C2668: 'log10': Mehrdeutiger Aufruf einer überladenen Funktion

    ich hab mir mal erlaubt es so zu schreiben:

    #include <cmath>
    
    unsigned int f(int X, bool count_minus = false)
    {
    	float log_10 = std::log10( float(abs(X)) );
    	unsigned int ret_val = unsigned int(log_10);
    	return ret_val + 1 + (count_minus && X<0);
    }
    

    test-aufruf:

    unsigned int a = f(INT_MIN);
    //a == 1
    

    der log-aufruf hier geht schief - in dem float steht irgend ein code, der sich mir nicht ganz erschließt - irgendwas mit IND001

    bb



  • theliquidwave schrieb:

    Dein Code "failt" bei 0 (Länge = 0) und Minuszahlen (Endlosschleife).
    Hier mal ein Fix 😉

    int get_length(int value)
    {
    	if (value == 0)
    		return 1;
    	
    	int ret_val = 0;
    	
    	if (value < 0)
    	{
    		value *= -1;
    		++ret_val;
    	}
    	
    	for(; value != 0; ++ret_val)
    		value /= 10;
    	
    	return ret_val;
    }
    
    get_length(-2147483648);
    

    :p



  • Michael E. schrieb:

    theliquidwave schrieb:

    Dein Code "failt" bei 0 (Länge = 0) und Minuszahlen (Endlosschleife).
    Hier mal ein Fix 😉

    int get_length(int value)
    {
    	if (value == 0)
    		return 1;
    	
    	int ret_val = 0;
    	
    	if (value < 0)
    	{
    		value *= -1;
    		++ret_val;
    	}
    	
    	for(; value != 0; ++ret_val)
    		value /= 10;
    	
    	return ret_val;
    }
    
    get_length(-2147483648);
    

    :p

    Das gibt aber auch kein falsches Ergebnis.
    Falls value*=-1 gar nicht benötigt wird, was zur Zeit vermutet wird.



  • unskilled schrieb:

    ich glaube kaum, dass es sich bei einer 32bit zahl überhaupt lohnen wird...

    alleine schon die ständigen umwandlungen wären für mich schon grund genug, es nicht zu verwenden...

    int g0(int const& X)
    {
        return log10( abs(X) ) +1 + (X<0);
    }
    

    Jo, hab das std:: vergessen, hinzukommt das ich X=0 nicht abfrage,
    lustigerweise funktionierte es bei mir trozdem (gcc), da ich es mit unsigned als Rückgabewert getestet habe und scheinbar -inf +1 zu null gecasted wird?!
    Ist das Compiler abhängig?
    Kann das jemand erklären?

    #include <iostream>
    #include <cmath>
    
    int main()
    {
        std::cout << std::log10(0) <<"\n"; //-inf0
        std::cout << (int)std::log10(0)<<"\n"; // -2147483648
        std::cout << (unsigned int)std::log10(0); // 0
        return 0;
    }
    


  • Was spricht gegen diese Lösung?

    unskilled schrieb:

    std::string get_int_as_string(int value)
    {
      std::stringstream ss;
      ss << value;
      return ss.str();
    }
    


  • Tachyon schrieb:

    Was spricht gegen diese Lösung?

    unskilled schrieb:

    std::string get_int_as_string(int value)
    {
      std::stringstream ss;
      ss << value;
      return ss.str();
    }
    

    Zu lahm.



  • Michael E. schrieb:

    Zu lahm.

    Wieviel lahmer? Zeitmessungen gemacht?



  • #include <iostream>
    #include <string>
    #include <sstream>
    #include <boost/random/linear_congruential.hpp>
    using namespace std;
    
    typedef unsigned __int64 u64; 
    
    #pragma warning(push) 
    #pragma warning(disable:4035) 
    u64 rdtsc() 
    { 
    	__asm rdtsc; 
    } 
    #pragma warning(pop)
    
    int getLength1(int arg)
    {
    	stringstream ss;
    	ss << arg;
    	return ss.str().length();
    }
    
    int getLength2(int arg)
    {
    	int ret = (arg < 0);
    
    	do
    		++ret;
    	while(arg /= 10);
    
    	return ret;
    }
    
    int main()
    {
    	const int n = 100000;
    	int result[n];
    	int (*func[2])(int) = { getLength1, getLength2};
    	boost::rand48 generator;
    
    	for(int i = 0; i < 10; ++i)
    	{
    		for(int j = 0; j < 2; ++j)
    		{
    			generator.seed(42);
    			for(int k = 0; k < n; ++k)
    				result[k] = generator();
    
    			u64 start = rdtsc();
    
    			for(int k = 0; k < n; ++k)
    				result[k] = func[j](result[k]);
    
    			u64 end = rdtsc();
    
    			if(j)
    				cout << end - start << "\n";
    			else
    				cout << end - start << " <-> ";
    		}
    	}
    }
    

    Intel Core i3-330M, Windows 7 Home Premium 64 Bit, Visual Studio 2008 SP1, Optimierung auf "Geschwindigkeit maximieren":

    /O2 /Oi /GL /I "d:\boost/boost_1_42" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FD /EHsc /MD /Gy /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /nologo /c /Zi /TP /errorReport:prompt
    

    Ausgabe:

    605812167 <-> 9224968
    573697862 <-> 9301400
    572169548 <-> 9157740
    578836805 <-> 9419872
    569198168 <-> 9235780
    562688192 <-> 9165412
    572129856 <-> 9244632
    573213868 <-> 9171600
    569073352 <-> 9297776
    568769208 <-> 9402188
    

    Macht also einen Faktor von etwa 60.



  • Michael E. schrieb:

    [...]Zu lahm.

    Zu lahm wofür? Es geht nicht um das Ermitteln der Ziffernzahl. Es geht um das Erstellen eines Images des gegebenen Integers...



  • Michael E. schrieb:

    Macht also einen Faktor von etwa 60.

    Wenn die Funktion mit allen Aufrufen nur einen winzigen Bruchteil des Gesamtprogramms ausmacht macht ein Faktor 60 den Kohl auch nicht fett und reduziert die Auswahl zwischen den beiden Möglichkeiten zur Geschmackssache.



  • edit: oh - mein fehler : D



  • Da die Zahlen endlich sind, ist eine Lookup-Table doch schneller. 😃



  • Eins vorneweg: Ich hab nicht gesehen, dass der OP schon mit Stringstreams herumwurschelt, sondern bin davon ausgegangen, dass es wirklich nur darum geht, die Anzahl der Ziffern herauszufinden. Denn Tachyon hat recht mit seiner Aussage.

    pumuckl schrieb:

    Wenn die Funktion mit allen Aufrufen nur einen winzigen Bruchteil des Gesamtprogramms ausmacht macht ein Faktor 60 den Kohl auch nicht fett und reduziert die Auswahl zwischen den beiden Möglichkeiten zur Geschmackssache.

    Versteh mich nicht falsch. Ich bin auch kein Freund vom frühzeitigen Optimieren und wähle sehr oft andere Wege als den schnellsten, aber hier ist es egal, für welche Version man sich entscheidet, auf den Rest des Codes hat das keine Auswirkungen. Auch sind beide Varianten in etwa "gleich schön", sodass man sich hier durchaus nach der Geschwindigkeit richten kann, auch wenns nachher bei der Programmausführung nicht auffällt.

    unskilled schrieb:

    for(int k = 0; k < n; ++k)
      result[k] = func[j](result[k]);
    

    klar, wenn vll eine "lange" zahl und dann nur noch ziffern untersucht werden, dass die schleife wahnsinnig schnell ist - ich nehme mal an, dass sich das ein wenig relativiert, wenn du längere zahlen nimmst...

    Das sind alles Zahlen mit fünf bis zehn Ziiffern. Wie willst du noch längere Zahlen in int speichern?



  • Michael E. schrieb:

    Das sind alles Zahlen mit fünf bis zehn Ziiffern. Wie willst du noch längere Zahlen in int speichern?

    mein fehler - hatte mich verguckt -.-
    habs mal wegeditiert...^^


  • Administrator

    Fellhuhn schrieb:

    Da die Zahlen endlich sind, ist eine Lookup-Table doch schneller. 😃

    Sowas vielleicht?

    #include <limits>
    
    template<typename T, std::size_t BIT>
    struct max_value_helper
    {
      static T const result = ((T)1 << BIT) + max_value_helper<T, BIT - 1>::result;
    };
    
    template<typename T>
    struct max_value_helper<T, 0>
    {
      static T const result = 1;
    };
    
    template<typename T>
    struct max_value // ich vermisse constexpr von C++0x
    {
    private:
      typedef std::numeric_limits<T> limits;
    
      static std::size_t const bits = std::numeric_limits<T>::digits;
      static std::size_t const sub = std::numeric_limits<T>::is_signed ? 1 : 0;
    
    public:
      static T const result = max_value_helper<T, bits - sub>::result;
    };
    
    template<typename T, T VALUE, std::size_t COUNTER = 0, bool CHECK = true>
    struct max_decimal_places_helper
    {
    private:
      typedef max_decimal_places_helper<T, VALUE / 10, COUNTER + 1, (VALUE > 0)> next;
    
    public:
      static std::size_t const result = 1 + next::result;
    };
    
    template<typename T, T VALUE, std::size_t COUNTER>
    struct max_decimal_places_helper<T, VALUE, COUNTER, false>
    {
      static std::size_t const result = 0;
    };
    
    template<typename T>
    struct max_decimal_places
    {
    private:
      typedef max_decimal_places_helper<T, max_value<T>::result / 10> helper;
    
    public:
      static std::size_t const result = helper::result;
    };
    
    template<typename T, std::size_t COUNT>
    struct e10
    {
      static T const result = e10<T, COUNT - 1>::result * 10;
    };
    
    template<typename T>
    struct e10<T, 0>
    {
      static T const result = 1;
    };
    
    template<typename T, std::size_t DECIMAL_PLACES>
    struct decimal_place_counter
    {
      static T const check = e10<T, DECIMAL_PLACES>::result;
    
      static std::size_t count(T val)
      {
        if((val < 0 && val > -check) || (val >= 0 && val < check))
        {
          return decimal_place_counter<T, DECIMAL_PLACES - 1>::count(val);
        }
    
        return DECIMAL_PLACES + 1;
      }
    };
    
    template<typename T>
    struct decimal_place_counter<T, 0>
    {
      static std::size_t count(T val)
      {
        return 1;
      }
    };
    
    template<typename T>
    std::size_t decimal_place_count(T val)
    {
      typedef max_decimal_places<T> places;
      typedef decimal_place_counter<T, places::result - 1> counter;
    
      return counter::count(val);
    }
    

    Grüssli 🤡 😃


Anmelden zum Antworten