Mit als String übergebenen mathematischer Funktion rechnen.



  • Hallo,
    die Suchfunktion ist momentan leider nicht verfügbar, glaube aber nicht daß so etwas schon mal gefragt wurde:

    Ich möchte einer C++ Funktion eine Formel (als String) übergeben, und anhand dieser Formel und zwei gemessenen Werten dann eine Regelgröße berechnen.

    z.B. a*4(3*4711)/0.0815*b2

    a und b sind hierbei die gemessenen Größen. Die Formel soll so als String (oder sonstwas, bin für Vorschläge offen) übergeben werden und das Ergebnis durch einsetzen der Werte a und b ermittelt werden.
    Ich wäre für Hilfe und Ideen dankbar, da ich momentan überhaupt keine Idee hab wie ich sowas machen könnte, da die Formel frei wählbar (entsprechend der C++ Syntax übergeben) sein soll.
    Für eure Bemühungen im Voraus besten Dank!

    Gruß
    Threaddy



  • 1. a und b im String mit replace durch die richtigen Werte ersetzen.
    2. Die Formel in Tokens aufteilen, das wären in deinem Fall:

    a - * - 4 - ^ - ( - 3 - * - 4711 - ) - / - 0.0815 - * - b - ^ - 2

    3. Bei der tiefsten Ebene zu rechnen beginnen, da die Formel ja immer korrekt übergeben wird ist da auch keine Prüfung notwendig. Die tiefste Ebene ist Ebene 1: (3*4711)

    4. Nach den Regeln der Kunst (Punkt vor Strichrechnung, etc.) dies in Zahlen umrechnen den op bestimmen und das Ergebniss stattdessen einsetzen. Dies führst du solange aus bist du die oberste Ebene berechnen kannst und fertig.

    Ein mathematischer Parser ist sehr aufwendig, wo genau haperts den?

    MfG SideWinder



  • schau dir mal den Taschenrechner von Stroustrup an (ist im Buch "Die Programmiersprache C++").
    Der sollte dir schonmal weiterhelfen.
    Hmm, find grad keinen Link zudem.
    Aber das Buch sollte man als C++ Programmierer sowieso neben der Bibel stehen haben 😉



  • Hi,

    wo ist denn mein Beitrag von gestern hingekommen??? Naja egal, so ist der Stand der Dinge:

    void main()
    {
    	string temp="200+2*30/40*5*600\0";
    	mathParser(temp);
    }
    
    inline double mathParser(string expression)
    {
    	const char* formula=expression.c_str();
    	int formulaLength=0;
    	//länge bestimmen
    	for (int i=0; formula[i]!=0; i++)
    		formulaLength++;
    	//array mit Zeigern auf char anlegen
    	char **token=new char*;	
    	//in der formel zu suchende Operatoren
    	char operators[7]={'+','-','*','/','(',')','^'}; //sqrt(x) = x^(1/2)  log=?
    	const int OPERATORCOUNT=7;
    	int tokencount, indexpos;
    	bool found=0;
    	tokencount=indexpos=0;
    	//erstes Token anlegen
    	token[tokencount]=new char[100];
    	for (i=0; i<=formulaLength ;i++)
    	{	
    		if (formula[i]!='\0')
    		{
    			//Prüfen ob aktuelle Position ein Operator ist
    			for (int j=0; j<OPERATORCOUNT; j++)
    				if (formula[i]==operators[j])
    					found=1;
    			if (!found)
    				token[tokencount][indexpos++]=formula[i];
    			else
    			{
    				//letztes Token abschließen
    				token[tokencount][indexpos]='\0';
    				indexpos=0;
    				//nächstes Token erstellen
    				token[++tokencount]=new char[100];
    				//Operator reinschreiben (incl Stringende-Zeichen)
    				token[tokencount][indexpos]=formula[i];
    				token[tokencount][indexpos+1]='\0';
    				//nächstes Token erstellen
    				token[++tokencount]=new char[100];
    				found=0;
    			}
    		}
    		//letztes StrinendeZeichen anhängen
    		token[tokencount][indexpos]='\0';
    	}
    
    	cout << "\ntoken0:" << token[0];
    	cout << "\ntoken1:" << token[1];
    	cout << "\ntoken2:" << token[2];
    	cout << "\ntoken3:" << token[3];
    	cout << "\ntoken4:" << token[4];
    	cout << "\ntoken5:" << token[5];
    	cout << "\ntoken6:" << token[6];
    	cout << "\ntoken7:" << token[7];
    	cout << "\ntoken8:" << token[8];
    	cout << "\ntoken9:" << token[9];
    	cout << "\ntoken10:" << token[10];
    	cout << "\n\nFertig!\n\n";
    	return 1;
    }
    

    Dies sollte eigentlich den übergebenen String in einelene char-Arrays zerlegen, wobei jedes einen Wert bzw. Operator enthält.
    Beim Ausführen krieg ich immer folgenden Fehler: "Debug assertin failed" (im Debugmode des Compilers), allerdings stimmt die Ausgabe dann.
    Im Release-Mode halt das gängige "Die Anwendung verweist auf Speicher in 0x000..", und hier stehen teilweise Wirre Zeichen mit drin.
    Also habe ich anscheinend irgendwo in falschen Speicherbereich geschrieben, ich komm jetzt aber um's verrecken nicht drauf wo ich da mist gebaut habe.
    Ach ja, daß ich die CharArrays immer mit "new char(100)" anlege ist erst mal so 'ne Zwischenlösung (mehr reservieren als man braucht kann nicht der Fehler sein denk ich).
    PS. Benutz MS VC++ 6.0 ist aber glaub ich hier nicht relevant.

    Wäre nett wenn mir jemand nen Tipp geben könnte.
    Wie immer im Voraus besten Dank!!!

    Gruß
    Threaddy



  • Tips:

    - Länge bestimmen: Bitte mit strlen() bzw. mit expression.length() aber nicht selber zählen.
    - Konstanten irgendwo oberhalb anbringen
    - Die Tokens am Ende über eine Schleife ausgeben

    Dein Absturzgrund:

    char **token=new char*;

    Du hast nun einen Zeiger der auf char-Zeiger zeigen kann. Weist ihm aber nur einen Zeiger zu, also:

    1. Würde höchstens ein Token möglich sein
    2. Jedes Token für sich benötigt auch noch Speicherplatz, dein Token hat aber keinen Speicherplatz.

    Deswegen:

    a) Du schlägst dich mit kompliziertem C-Speichermanagement herum
    b) Du verwendest statt Arrays std::vector und statt deinen Strings std::string und kannst Tokens einfach über mytokens.push_back(newtokenasstring); einfügen.

    MfG SideWinder



  • Besorg dir ein Buch zu Compilerbau, da kriegst du solche Sachen dann ganz leicht hin, ohne irgendwas zusammenzuschustern, was dann meistens nicht sonderlich gut funktioniert (also in vielen Fällen geht's, in manchen nicht, oder so)



  • hier hab ich was zum Thema geschrieben(auf der 2. seite gibts auchn buchtipp



  • Hallo

    SideWinder schrieb:

    Dein Absturzgrund:

    char **token=new char*;

    Du hast nun einen Zeiger der auf char-Zeiger zeigen kann. Weist ihm aber nur einen Zeiger zu, also:

    1. Würde höchstens ein Token möglich sein
    2. Jedes Token für sich benötigt auch noch Speicherplatz, dein Token hat aber keinen Speicherplatz.

    Stimmt, jetzt wo du's sagst 🙄 (ich dödel):
    char **token=new char*[formulaLength];

    Daß es mit Vectoren einfacher ist ist mir klar, wollte das Teil eigentlich zur berechnung von Werten in einem Regelkreis (und das soll so schnell wie möglich laufen) verwenden, und darum auf Vectoren verzichten (und ob die deque schneller is?).
    Mit den restlichen Anmerkungen hast du natürlich auch recht, waren alles noch Relikte aus vorherigen Tests.

    Die Buchempfehlungen werd ich mir mal zu Herzen nehmen, da ich mich demnächst sowieso mit Compilerbau beschäftigen muß.

    An alle noch mal vielen Dank!

    Gruß
    Threaddy


Anmelden zum Antworten