Diskretisieren von Messwerten (optimieren)



  • Hi,
    ich habe mir folgendes Stückchen Code zurecht gebastelt um damit Messwerte in ein Feld zu sortieren.

    int diskret(double in, double min, double max, int slots)
    {
    //in Messwert
    //min, max Intervall
    //slots Maximaler Index
    	if((in >= min) && (in < max))
    	{
    		double b = (max - min) / (slots + 1);
    		double tmp = in - min;
    		tmp = tmp / b;
    		return int(tmp);
    	}
    	else
    		return -1;
    }
    

    Ich erhalte jetzt zu einem eingegebenen Wert den Feldindex.

    Mich würde nun interessierem, ob man hier noch etwas mehr Geschwindigkeit rausholen kann und wie.

    Danke



  • du könntest die Zwischenvariablen weglassen und die ganzen Zwischenschritte zu einer Rechnung zusammenfassen:

    return (slots+1)*((in - min) / (max - min));
    

    Sonst sieht das in meinen Augen schon recht optimal aus.



  • Ok, danke.
    Ich dachte da evtl noch an den if-Block, aber da gibt es wohl eine Möglichkeit oder?



  • Du könntest den if() natürlich auch weglassen und stattdessen einen Kommentar "das Verhalten ist undefiniert, wenn in außerhalb des Intervalls [min,max] liegt" in die Dokumentation aufnehmen 😋



  • daishi schrieb:

    Mich würde nun interessierem, ob man hier noch etwas mehr Geschwindigkeit rausholen kann und wie.

    Hallo Daishi,

    Du kannst Berechnungen, die nicht mit jedem neuen Messwert gemacht werden vorher machen und das Zwischenergebnis abspeichern.
    Ich unterstelle mal, dass sich weder die Anzahl der slots noch das Intervall [min,max) ändert, während die Messwerte reinkommen.

    Dann ist Dir mit dieser Klasse vielleicht geholfen

    class Diskretisierer
    {
    public:
        Diskretisierer( int nSlots, double minVal, double maxVal )
            : m_nSlots( nSlots )
            , m_min( minVal )
            , m_max( maxVal )
            , m_b( (m_max - m_min) / m_nSlots )
        {}
    
        int idx( double x ) const
        {
            const int idx = int( (x - m_min) / m_b ); // s.Kommentar unten
            if( x < m_min || idx >= m_nSlots )
                return -1;
            return idx;
        }
    private:
        int     m_nSlots;
        double  m_min;
        double  m_max;
        double  m_b;
    };
    

    Die Anwendung ist so ähnlich wie hier:

    int main()
    {
        using namespace std;
        Diskretisierer dis( 7, 5.0, 12.0 );
        for( double x = 4.6; x < 13.0; x += 0.4 )
            cout << x << " idx: " << dis.idx( x ) << endl;
        return 0;
    }
    

    Der Wert 'm_b' wird nur einmal berechnet und entspricht Deinem 'b' in 'diskret'. Dann habe ich noch 'slots' maximaler Index durch 'bSlots' =Anzahl der Slots ersetzt - also nSlots = slots + 1.
    Weiter ist mir aufgefallen, dass das 'min' bei der Berechnung des slot-Indexes nicht berücksichtigt wird. Ich meine, dass Dein Prog nicht wie gewünscht funktioniert, falls 'min' einen Wert !=0 annimmt.

    Die Abfrage

    if( x < m_min || idx >= m_nSlots )
    

    ist ernst gemeint. Ein

    if( idx < 0 || idx >= m_nSlots )
    

    liefert falsche Werte für ein 'x' knapp unterhalb von 'min', da z.B. int( -0.5 ) auch wieder 0 ist.

    Gruß
    Werner



  • Danke erstmal an die beiden fleißigen Helfer.
    Die Idee mit der Klasse war echt klasse. 😃
    Bei der Performance konnte ich ca. 3% gut machen.

    Ein Fehler ist mir noch aufgefallen, das +1 bei slots muß weg.

    Dann ist aber noch eine Sache, die ich nicht verstehe.

    Werner Salomon schrieb:

    Der Wert 'm_b' wird nur einmal berechnet und entspricht Deinem 'b' in 'diskret'. Dann habe ich noch 'slots' maximaler Index durch 'bSlots' =Anzahl der Slots ersetzt - also nSlots = slots + 1.
    Weiter ist mir aufgefallen, dass das 'min' bei der Berechnung des slot-Indexes nicht berücksichtigt wird. Ich meine, dass Dein Prog nicht wie gewünscht funktioniert, falls 'min' einen Wert !=0 annimmt.

    Die Abfrage

    if( x < m_min || idx >= m_nSlots )
    

    ist ernst gemeint. Ein

    if( idx < 0 || idx >= m_nSlots )
    

    liefert falsche Werte für ein 'x' knapp unterhalb von 'min', da z.B. int( -0.5 ) auch wieder 0 ist.

    Ich habe deine Klasse und meine Funktion mal laufen lassen. Beide liefern die gleichen Ergebnisse und der von dir beschriebene Fehler tritt nicht auf.
    Deshalb hänge ich hier nochmal den voll kommentierten Quelltext rein.

    int diskret(double in, double min, double max, int slots)
    {
    //in		Messwert
    //min, max	Intervall
    //slots		Maximaler Index 	
    	if((in >= min) && (in < max))	//Probe ob Wert im Intervall
    	{
    		double b = (max - min) / (slots);	//Groesse eines Slots im Wertebereich
    		double tmp = in - min;	//Werte auf das Intervall [0..max-min) bringen
    		tmp = tmp / b;	//Index ermitteln
    		return int(tmp);
    	}
    	else
    		return -1;	//in ausserhalb des Intervalles
    }
    


  • Werner Salomon schrieb:

    Weiter ist mir aufgefallen, dass das 'min' bei der Berechnung des slot-Indexes nicht berücksichtigt wird. Ich meine, dass Dein Prog nicht wie gewünscht funktioniert, falls 'min' einen Wert !=0 annimmt.

    Guck doch mal ganz genau hin - min wird verwendet 😉 (besonders durlich siehst du das, wenn du meine zusammengekürzte Version betrachtest)



  • CStoll schrieb:

    min wird verwendet

    Stimmt - hast Recht! ich hatte mich vertan.

    Gruß
    Werner


Anmelden zum Antworten