[gelöst] Vector ist wesentlich langsamer als Array?



  • Wollte hier auch keinen Flamewar lostreten. Ich weiß des es einige compiler unterstützen, dachte aber vorallem eher ältere. Find sowas zumindest nicht schön. Ist aber auch egal. (Das andere Problem war, das es - eigentlich - im standard kein string::operator!= gibt, lies sich aber leicht durch string.compare ersetzen)

    Das eigentliche Problem ist, ohne Testdaten kann ich den Profiler halt nicht laufen lassen, und würde mich schon interessieren was da soviel performance kostet. Spekulieren kann man ja viel. Wenn es aber allgemein auftritt, kann ich mir sowas ja durchaus selbst erstellen. Welche Dimensionen hat so ein typischer Fall?



  • kleiner Troll schrieb:

    (Das andere Problem war, das es - eigentlich - im standard kein string::operator!= gibt, lies sich aber leicht durch string.compare ersetzen)

    Türlich gibts den.


  • Mod

    Also es fällt mir schon beim überfliegen auf, dass hier, wie von anderen bereits vermutet, jede Menge versteckte Kopien von großen Objekten gemacht werden, außerdem wird die Dynamik der Vectoren, wenn ich das recht sehe, überhaupt nicht benutzt, so dass ein std::array oder ein 1D-Vectorwrapper das richtige wären.

    Ein Fall vom berüchtigten

    Bjarne Stroustrup schrieb:

    C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.



  • 👍



  • Türlich gibts den.

    Tschuldige, falsch geschaut, hat bei mir aber trotzdem nicht kompiliert, ka wieso, is mir atm auch egal.



  • 314159265358979 schrieb:

    zeusosc schrieb:

    memcpy((void*)&d,(void*)&i,8);
    

    Wer hat dir denn beigebracht, dass man hier casten muss? Wie ekelhaft und gleichzeitig verwirrend.

    neee,.. entschuldige es war gemeint

    anstelle:

    __get_sc__int(_8fak_inv,_tF);
    	ret=_tF;
    
    	ret*=_sq_x;
    	__get_sc__int(_6fak_inv,_tF);
    	ret+=_tF;
    
    	ret*=_sq_x;
    	__get_sc__int(_4fak_inv,_tF);
    	ret+=_tF;
    

    einfach:

    ret=(double)_8fak_inv;
    
    	ret*=_sq_x;
    
    	ret+=(double)_6fak_inv;;
    
    	ret*=_sq_x;
    
    	ret+=(double)_4fak_inv;;
    

    Damit spart man sich auch noch die memcpy, da der Compiler das direkt als double
    interpretiert...

    grüüße



  • Wenn du noch die C++-Casts verwendest, bin ich ganz zufrieden. 😉



  • Ich bin wahrlich kein erfahrener Programmierer. Das ist ein Fakt.
    Es ist nur so, dass ich keine Alternative produzieren kann.

    vector< vector<double> > M;
    -> die erste Schicht M[i] gibt mir eine variable Anzahl an Schichten an
    -> die zweite Schicht M[i][j] gibt mir für jede einzelne Schicht wieder eine
    variable Anzahl an Neuronen an.
    Diese werden im Konstruktor festgelegt und an das private Attribut übergeben.
    (this->M). Danach wird der Konstuktor beendet und learning wird aufgerufen.

    Ich bin nur so weit, dass ich wenn Arrays benutzte eine konstante Anzahl an Elementen festlegen muss. (-> ist ja nicht gegeben) Weiterhin, wenn ich im Konstruktor mit Referenzen umgehe, wird doch nach dem Konstruktor sämtliche Daten die dort erstellt worden gelöscht. Und sollte ich die Referenz als Attribut gespeichert haben, so deutet sie nach Beendigung des Konstruktors auf einen "toten" Wert. Also weiß ich nicht wie ich die Attribute this->M und this->w auf Arrays umstellen kann. Mehrdimensionale Arrays können meines Wissens nur als Referenzen erstellt werden.
    -> Ich sehe in meinem begrenzten Wissen also keine Alternative.

    Ist es vielleicht möglich, dass einfach weniger Vorwissen in den Kommentaren vorausgesetzt wird, damit ich eine etwas praktischere Anleitung herauslesen kann, um mein Problem zu lösen? Ich komm einfach nicht wirklich weiter. Für Literaturempfellungen bin ich auch höchst dankbar.



  • ret=static_cast<double>(_8fak_inv);
    
    ret*=_sq_x;
    
    ret+=static_cast<double>(_6fak_inv);
    
    ret*=_sq_x;
    
    ret+=static_cast<double>(_4fak_inv);
    

    @ComputerCarl:

    Ok,.. also nach der Konstruktion hast Du aber eine fixe anzahl an Schichten und
    Neuronen?



  • Hat mir das mit dem operator!= doch keine Ruhe gelasen, der Grund warums bei mir nicht ging war, das #include <string> "gefehlt" hat - string selbst wurde wohl aber über einen anderen include mitgezogen. Beim MSVC wohl nur string, bei gcc und dev++ wohl auch die globale funktion. *Peinlich von mir*



  • Du musst übrigens nicht allen Membervariablen und Funktionen this-> voranstellen, das geht in den meisten Fällen auch ohne. 🙂



  • zeusosc schrieb:

    @ComputerCarl:
    Ok,.. also nach der Konstruktion hast Du aber eine fixe anzahl an Schichten und
    Neuronen?

    Genau! Nach dem Konstruktor sind alle Attribute fest in der Anzahl ihrer Dimensionen.



  • Wenn Dir M[i] Deine Schicht indiziert und M[i][j] Dein Neuron
    brauchst Du also "nur" ein zur Initialisierungszeit dynamisches array...

    Dein Neuron hat welche Parameter?

    typedef struct _neuron
    {
    double* weight; // gewichte der eingänge
    
    LPVOID _ue_func; //zeiger auf eine Gewichtungsfunktion (übertragungsfunktion)
    LPVOID _outbarrier_func;// Ausgangsschwellenfunktion, also aktivierungsfunktion
    }
    

    oder sind die Gewichte bei Dir schon mit M[i][j][w] gegeben?

    grüße
    ------
    edit:
    ahh ok,.. ich sehe es gerade,..
    ich bastele mal was



  • Wenn Dir M[i] Deine Schicht indiziert und M[i][j] Dein Neuron
    brauchst Du also "nur" ein zur Initialisierungszeit dynamisches array...

    -> Das sehe ich noch nicht, aber das muss nichts heißen.
    Also kurz ich weiß nicht, wie ich die eine Dimension reduzieren kann.
    Ich mein, ich könnte mir die Anzahl der Schichten mit der Anzahl der Neuronen
    zwischen-speichern und somit die "Referenzierung" auf ein Index selber zusammen basteln, aber ich weiß nicht ob das gemeint ist.

    Dein Neuron hat welche Parameter?

    typedef struct _neuron
    {
    double* weight; // gewichte der eingänge
    
    LPVOID _ue_func; //zeiger auf eine Gewichtungsfunktion (übertragungsfunktion)
    LPVOID _outbarrier_func;// Ausgangsschwellenfunktion, also aktivierungsfunktion
    }
    

    oder sind die Gewichte bei Dir schon mit M[i][j][w] gegeben?

    Na ja nicht ganz... ein Neuron hat soviele Gewichte wie Neuronen in der vorhergehenden Schicht. Also jede Verbindung von Neuron j aus Schicht i
    führt zu Neuron k in Schicht i+1. Die Gewichte sind in w[i][j][k] gespeichert.
    wTx in activate liefert mir somit die Aktivierung durch die Vorgänger-Neuronen und der tanh(beta * (wTx - bias)) bestimmt somit die Weiterleitung in die Nächste Schicht. Diese wird in M[i+1][k] gespeichert.

    Welche Funktionen LPVOID ... übernehmen sollen kann ich erahnen, sehe aber nicht die Notwendigkeit.



  • Ich werde jetzt bis morgen früh erst mal das Feld räumen.
    Sollten noch Fragen an mich kommen also nicht warten. Ich
    werde heut nicht mehr antworten.
    Um aber vielleicht ein besseres Bild von solch einem Netz
    zu schaffen wollte ich nur ebenmal eine graphische Darstellung
    posten. Auf dieser Seite wäre solch ein Netz, was eigentlich
    in meinem Code implementiert wurde. Text der Seite hab ich nicht
    mehr gelesen nur die Darstellung ist denke ich hilfreich.

    http://www.google.de/imgres?imgurl=http://193.25.32.158/fb2/prof/skrueger/images/stories/neuronetze/rendite.gif&imgrefurl=http://www.kolleg.wi.hs-anhalt.de/fb2/prof/skrueger/index.php%3Foption%3Dcom_content%26view%3Darticle%26id%3D72%26Itemid%3D85&usg=__Wf5XkEsDvPGlCUYNBuxG8SVVb9k=&h=226&w=462&sz=26&hl=de&start=0&zoom=1&tbnid=Y-uU2AeUVBalsM:&tbnh=88&tbnw=179&ei=fwcjT67FA86Rswbkt5yTDw&prev=/search%3Fq%3Dk%C3%BCnstliches%2Bneuronales%2Bnetz%26um%3D1%26hl%3Dde%26sa%3DN%26biw%3D1920%26bih%3D917%26tbm%3Disch&um=1&itbs=1&iact=rc&dur=176&sig=107543848169332014707&page=1&ndsp=45&ved=1t:429,r:14,s:0&tx=74&ty=42

    Hier das Bild isoliert:
    http://193.25.32.158/fb2/prof/skrueger/images/stories/neuronetze/rendite.gif



  • Ach schade,.. bin gerade fertig geworden,...

    Naja vlt können die anderen das ja mal auseinander nehmen:

    //#######################################################################################################
    // Base Array class deklaration
    //#######################################################################################################
    
    template<typename T>
    class _base_array
    {
    private:
    	T *_ptr;
    	unsigned int size;
    
    	bool _malloc(unsigned int Size);
    	void _free(void);
    	void _clear_all(void);
    public:
    	_base_array();
    	_base_array(unsigned int Size);
    	~_base_array();
    	void reserve(unsigned int Size); // just call it ONCE
    	unsigned int _nr_of_elements(void);	// returns the absolute number of accessable elements
    	unsigned int _size(void);	//returns the size of array in Bytes
    	T & operator[](int Index);
    };
    
    //#######################################################################################################
    // Base Array class definitions
    //#######################################################################################################
    template<typename T>
    bool _base_array<T>::_malloc(unsigned int Size)
    {
    	bool bRet=false;
    	if(	this->_ptr ) return bRet;
    
    	this->_ptr=reinterpret_cast<T*>(malloc(sizeof(T)*Size));
    	if(	!this->_ptr ) 
    	{
    		this->size=0;
    		return bRet;
    	};
    
    	this->size=Size;
    
    	for(int i=0; i<Size; i++)
    		(*(this->_ptr+i))=T();
    
    return !bRet;
    };
    
    template<typename T>
    void _base_array<T>::_free()
    {
    if(!this->_ptr)
    {
    	this->size=0;
    	return;
    };
    
    free(reinterpret_cast<void*>(this->_ptr));
    
    this->_ptr=reinterpret_cast<T*>(0);
    this->size=0;
    };
    template<typename T>
    void _base_array<T>::reserve(unsigned int Size)
    {
    	this->_malloc(Size);
    };
    
    template<typename T>
    void _base_array<T>::_clear_all()
    {
    	this->size=0;
    	this->_ptr=reinterpret_cast<T*>(0);
    };
    
    template<typename T>
    _base_array<T>::~_base_array()
    {
    	this->_free();
    	this->_clear_all();
    };
    
    template<typename T>
    _base_array<T>::_base_array()
    {
    	this->_clear_all();
    };
    
    template<typename T>
    _base_array<T>::_base_array(unsigned int Size)
    {
    	this->_clear_all();
    
    	this->_malloc(Size);
    };
    
    template<typename T>
    unsigned int _base_array<T>::_nr_of_elements()
    {
    	return this->size;
    };
    
    template<typename T>
    unsigned int _base_array<T>::_size()
    {
    	return this->size*sizeof(T);
    };
    
    template<typename T>
    T & _base_array<T>::operator [](int Index)
    {
    	if((Index <0 )|| (static_cast<unsigned int>(Index) > this->size-1)) 
    		return *(new T());
    
    	return *(this->_ptr +Index);
    };
    //#######################################################################################################
    
    typedef _base_array<int> _bai;
    typedef _base_array<_bai> _cai;
    typedef _base_array<_cai> _dai;
    
    //#######################################################################################################
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	_bai b(12);
    	_cai c(12);
    	_dai d;
    	d.reserve(12);
    
    	for(int i=0; i<12; i++)
    	{
    		b[i]=i;
    		c[i].reserve(12);
    		d[i].reserve(12);
    	};
    
    	for(int x=0; x<12; x++)
    	{
    		for(int y=0; y<12; y++)
    		{
    			d[x][y].reserve(12);
    
    		}
    	};
    
    	for(int x=0; x<12; x++)
    	{
    		for(int y=0; y<12; y++)
    		{
    			for(int z=0; z<12; z++)
    			{
    				d[x][y][z]=x+y*12+z*12*12; //weiß nicht ob die rechnung richtig ist,...
    			}
    		}
    	};
    
    	__debugbreak();
    
    	return 0;
    }
    

    grüße



  • Warum benennst du deine Klassen so grausam mit dem _ als Präfix?



  • Ja,..
    Warum machen andere das nicht?
    _Weil _man _die _Freiheit _hat das zu tun und zu lassen was man will,..
    ... und ausserdem ließt und schreibt sich das für mich leichter,...
    Ansonste fällt mir nicht mehr ein..



  • zeusosc schrieb:

    Warum machen andere das nicht?

    Weil alle Bezeichner vom Standard reserviert sind, die mit einem Unterstrich starten auf welchen ein Großbuchstabe folgt. Ok, deine Bezeichner sind zwar nicht nicht standardkonform, aber doch mehr als unüblich. Vor allem für Klassen und Funktionen. Da sind insgesamt noch so einige Hauer drin, aber da will ich jetzt nicht drauf eingehen, irgendjemand nimmt sich bestimmt die Zeit. 😉



  • Ok,..

    soweit ich weiss folgt bei mir auf den Unterstrich aber ein
    kleiner Buchstabe bzw. eine Zahl.
    Daher unterscheidet sich das von dem reservierten,..

    Hauerdrinn?

    jetzt bin ich neugierig,... auslernen will ich ja auch nicht,...


Anmelden zum Antworten