Java Objekt in C++-Routine auswerten?

Hey, nachdem ihr mir bei meinem Matrizenproblem so gut geholfen hat kommt diesmal eine etwas kompliziertere Frage.

Wir haben ein Projekt, bei dem jetzt auch native Calls in Spiel kommen sollen.
Das ganze läuft bis jetzt mit Antlr4.

Ich habe also eine Antlr4 Grammatik, die mathematische Funktion und Rechnungen erkennt und auswertet.
Also sowas wie (3+5*3)/9 oder f(x)=x^2; f(5); und Ähnliches. Der von Antlr4 generierte Parser baut mir also schöne Bäume, die ich dann mit einem Listener leicht auswerten kann.

Nun soll das Projekt so ausgeweitet werden, dass auch Integrale und Ableitungen berechnet werden. Das ganze soll aber in einer C+±Routine passieren.
Ich habe in meinem Java Projekt eine Klasse „Function.java“. Die Klasse sieht so aus:

{

	ParseTree vars;
	ParseTree term;
	ParseTreeWalker walker;

public double eval(double... args) throws IllegalArgumentException,
			RecognitionException {

...
}

Ich speichere also praktisch die Bäume weg.
Einmal den Variablenbaum und einmal den Expression-Baum.
In etwa so kann man sich das vorstellen:

In der eval-Methode werden praktisch bei einem Funktionsaufruf wie f(5, 7) die Werte 5 und 7, den Variablen a und b zugewiesen.
Danach läuft der TreeWalker einfach über den Expressiontree und mein Listener wertet die ganze Gleichung aus. So weit, so schön.

Die Grenzwerte sollen wohl über die Taylorreihe ausgrechnet werden, nur mein Problem ist, wie ich überhaupt die C+±Klasse aufrufen soll.
Ich weiß, das man JNI nutzen soll, aber ohne jegliches Hintergrundwissen frag ich mich, wie man ein Java Objekt(in diesem Fall ein Objekt der Klasse „Function“, an eine C-Routine übergeben soll.
Es heißt:

Mit Hilfe von gekapselten C Funktionszeigern und einer darauf abge-
stimmten C++ Funktionsklasse lassen sich effiziente Methoden
entwickeln, um beliebige C und Java Funktionen numerisch zu differenzieren
und bestimmte Integrale auszuwerten

Die eigentliche Frage, die ich mir also stelle ist, wie man es anstellt eine Funktion(die ja eigentlich ein Java Objekt ist) in C++ auszuwerten. Es hat anscheinend etwas mit dem überladen des ()-Operators zu tun.
Aber in C++ steht mir ja kein Listener oder TreeWalker zur Verfügung, die momentan das Rechnen für mich übernehmen, deswegen frag ich mich, wie man da das Integral oder den Differenzenquotienten berechnen soll.

Vllt hat da jemand ein kleines Beispiel, wie man sowelche Aufgaben an C++ Routinen „weitergibt“.

Grüße

Moin,

Du benötigst JNI!
beispielsweise: https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html

Gruß
Klaus

Stellt sich erst mal die Frage: WARUM - nur zum üben?

Geht natürlich nur mit JNI.

Hey, danke schonmal.
Das Tutorial werd ich mir gleich nochmal durchlesen.

Die Frage nach dem Warum hab ich mir auch schon öfters gestellt. In Java hätte ich es dank generierten Trees und TreeWalker einigermaßen leicht hinbekommen. Denke deswegen mal, dass das nur zur Übung dienen soll.
Leider wird an der Uni auch kein C++ gelehrt (zmdst hatte ich noch keine C++ Vorlesung), sodass ich mir das auch noch selbst aneignen muss.
Also erstmal Versuchen den Grenzwert zu berechnen mit einem Java Funktionsobjekt und dann schauen ob ich das mit Antlr noch alles verknüpft kriege.

Hab immerhin noch eine Woche Zeit ^^

Aber in C++ steht mir ja kein Listener oder TreeWalker zur Verfügung, die momentan das Rechnen für mich übernehmen, deswegen frag ich mich, wie man da das Integral oder den Differenzenquotienten berechnen soll.

Welche Integralarten musst du den überhaupt ausrechnen? Was stellt dir das ganze zur Verfügung? Was gibt’s schon fertig?

Der Frage von Bleiglanz würde ich mich anschließen. Da diese Frage aber SO nahe liegend ist, hätte ich jetzt vermutet, dass es da irgendeine Lib in C++ gibt, die du da gerne verwenden würdest…?

Wenn das nur zur Übung sein soll: Auf C+±Seite über JNI mit Java-Objekten rumzuhantieren kann ziemlich frickelig sein. Also, es geht, natürlich aber das, was man in Java mit

someObject.getSomething().doSomething(123);

einfach so hinschreibt, kann über JNI locker mal 30 Zeilen haben, und man kann auch einiges falsch machen.

(Das soll nicht entmutigen - nur ein neutraler Hinweis sein. Es kann natürlich nicht schaden, das “mal gemacht zu haben”. Aber nicht umsonst ist die allgemeine Empfehlung, die Schnittstellen zwischen Java und C++ möglichst klein und einfach zu halten - in Beide Richtungen, also sowohl wenn man von Java aus eine C-Funktion aufrufen will, als auch in der umgekehrten Richtung. (Für das Aufrufen von C-Funkionen aus Java heraus gibt’s auch etliche Tools und Libs, die das einfacher machen. Aber für die umgekehrte Richtung ist mir nichts spezielles bekannt (bzw. müßte ich auch erst suchen)). In dem Zusammenhang könnte auch die JIA von JNI interessant sein: The Invocation API - konzeptuell geht es DA erstmal darum, eine komplette JVM von C aus zu bootstrappen, aber natürlich mit dem Ziel, von dort aus dann Java-Funktionen aufzurufen)

[quote=Tarrew]Leider wird an der Uni auch kein C++ gelehrt (zmdst hatte ich noch keine C++ Vorlesung), sodass ich mir das auch noch selbst aneignen muss.
Also erstmal Versuchen den Grenzwert zu berechnen mit einem Java Funktionsobjekt und dann schauen ob ich das mit Antlr noch alles verknüpft kriege.[/quote]

Lustig (und gar nicht mal so schlecht): Eine Vorlesung bei der man zur Übung

  1. Grammatiken mit ANTLR erstellen UND

  2. C++ Funktionen native aus Java heraus aufrufen soll UND

  3. noch schnell nebenher C++ lernen muss (für 2.)

Gibt einfach keinen Sinn, wie heißt denn das Fach? Was soll man denn dabei lernen - drei völlig verschiedene Sachen auf einmal?

Da sind wohl die Navy-Seals der Informatikstudenten in der Ausbildung.

Fertig ist eine Antlr Grammatrik mit ensprechendem Java Programm die Funktionen einlesen kann und Berechnungen ausführen kann.
Die generierten Funktionsbäume werden in einer Klasse Funktion als Attribute gespeichert.
Hinzukommen soll zB:
Man hat eine Funktion f(x)=x^2; Dann soll es eine Funktion differenziere(Function fct, double value) geben. Für differenziere(f(x), 2) soll die Funktion also 4 zurückgeben. Mit Integralen dann genauso. Die Funktion soll aber in C++ geschrieben sein und aus Java aufgerufen werden.

[QUOTE=Bleiglanz;106626]Lustig (und gar nicht mal so schlecht): Eine Vorlesung bei der man zur Übung

  1. Grammatiken mit ANTLR erstellen UND

  2. C++ Funktionen native aus Java heraus aufrufen soll UND

  3. noch schnell nebenher C++ lernen muss (für 2.)

Gibt einfach keinen Sinn, wie heißt denn das Fach? Was soll man denn dabei lernen - drei völlig verschiedene Sachen auf einmal?

Da sind wohl die Navy-Seals der Informatikstudenten in der Ausbildung.[/QUOTE]

Die Vorlesung heißt „Höhere Programmierkonzepte“.
Morgen gibt es anscheinend nochmal eine kleine Einführung in das Thema. Zmdst sollten wir uns Fragen notieren, die dann morgen besprochen werden.

Denke danach herrscht etwas mehr Klarheit und ich kann meine Fragen hier nochmal konkreter formulieren.
In der Tat die härteste Vorlesung, die ich bisher hatte :wink:

Stelle mal die Frage, dass das unmöglich ist…

Entweder

  1. das ganze soll voll symbolisch sein - so wie Wolfram Alpha - dann wurde man f’(2) einfach durch Auswerten eines Terms erhalten

oder

  1. man evaluiert (f(x)-f(x+h))/h für hinreichend kleine h - dann muss man eine Fehlerabschätzung vorgeben etc → da kommt NIE exakt die Zahl 4 dabei raus

Ich nehme mal an, dass 2. gemeint ist.

Aber wozu mit Java-ANTLR herumwursteln - wie soll man „die Funktion“ dann durch einen JNI-Methodenaufruf an ein C++ Programm übergeben??

[QUOTE=Bleiglanz]
Aber wozu mit Java-ANTLR herumwursteln - wie soll man “die Funktion” dann durch einen JNI-Methodenaufruf an ein C++ Programm übergeben??[/QUOTE]

Ja ich denke auch mal das 2. gemeint ist.
Denke mal so ähnlich wird das mit dieser Taylorreihe auch gehen.

Und genau die Frage stelle ich mir.
Ich kenne mich mit C++ jetzt nicht aus muss ich gestehen, aber selbst wenn ich das Objekt irgendwie “rüberkrieg”, wie ich dann damit rechnen soll.

In Java kann ichs ja auch nur dadurch, dass der TreeWalker mich benachrichtigt. Also bei 5+5 wird dann so ein Baum aufgebaut:

/
5 5

Der Walker geht in die 5 und ruft in meinem Listener die “enterNumber” Methode. Ich pushe die Number dann auf einen Stack und der Walker geht in die nächste 5. Ich pushe wieder auf den Stack.
Dann komm ich in die “exitAddition” Methode und addiere einfach die obersten beiden Stackelemente.

In der C++ Routine steht mir ja weder Listener noch Walker zur Verfügung.
Ist mir noch ein Rätsel, wie ich dann einen Grenzwert ermitteln soll. Aber ich denke/hoffe, das kommt morgen alles zur Sprache.

Da es wirklich seltsam wäre, wenn ihr nur für die Aufgabe auch noch C++ lernen müsstet, könnte es sein, dass euch morgen der C+±Teil einfach vom Dozenten zur Verfügung gestellt wird?

Würde mich überraschen, da in der Aufgabenstellung explizit davon gesprochen wird, dass wir die .cpp Files entwickeln sollen.
Also “C++” lernen ist vllt auch etwas übertrieben ausgedrückt von mir.
Es geht ja “nur” um 2 Klassen. Also vllt eher “C++ Kenntnisse in einem bestimmten Teilgebiet” erwerben ;D

Vllt gibts in C++ ja auch eine Art " ScriptEngineManager" wie bei Java, der einen “Rechnungs”-String ausrechnen kann. Bin auf jeden Fall auf morgen gespannt.

Ergibt irgendwie alles keinen Sinn:

Den Baum des Funktionsterms via ANTLR in Java dargestellt

Mit einem C++ Teil die Ableitung der zu diesem Term gehörenden Funktion ermitteln

Kann so nicht passen, frag lieber mal ganz genau nach!

Ja, werde morgen nochmal fragen.
Zmdst heißt es:
„Der finale Test erfolgt gegen einen zur Verfügung gestellten JUnit Test, der […] aus einerZeichenkette geparste AntLR Funktionen differenziert und integriert.“

Werde mich morgen, nachdem ich genaueres weiß, nochmal melden.
Kann mir aber vorstellen, dass das eine stressige Woche wird :wink:

Sooo, hatte grad die “Vorlesung”, der Prof war leider nicht da.
Kann also nicht wirklich mit neuen Informationen kommen.

Falls jemand mal eine genauere Beschreibung des Problems sehen will:
Link und Text entfernt

Das schwierige ist eigentlich nur so einen Grenzwert irgendwie in C/C++ zu errechnen, das “verbinden” mit dem Java-Code krieg ich dann wohl irgendwie hin. Aber vllt hat jemand einen Tipp für die 1. Aufgabe.

Grüße

Hmja, da sind schon einige Stubs da. Es geht wohl darum, das, was unter “Numerik” zusammengefasst ist, mal auszuimplementieren…

Genau das ist ja eig. die Frage.
Ich brauche ja irgendeine Datenstruktur bei der ich rechnen kann.
In Java kann ich ja nur einen String “5+5-3*2” auswerten, da Antlr mir Bäume generiert und so weiter.

In C++ steht mir ja nichts zu Verfügung erstmal. Gibts da eine Möglichkeit eine bestimmte Struktur ausrechen zu lassen?
Ich komme ja nicht unmittelbar von einem String auf eine Rechnung die C++ irgendwie ausrechen kann. Oder doch? Vllt ist das auch die falsche Frage für ein Java-Forum ;p Oder es ist so simpel, dass ich es übersehe …

Ich habe nicht die komplette Aufgabenstellung Wort für Wort gelesen, aber … was veranlasst dich zu der Annahme, dass du Terme auswerten sollst? Also, ANTLR selbst ist ja schon ein ziemliches Brett. Aber wenn ich das richtig sehe, dreht sich die gesamte Aufgabe um die “Function”, und die macht nichts weiter, als für einen gegebenen “double” einen neuen “double” zurückzugeben. Und eine beliebige Implementierung davon soll dann (rein numerisch, NICHT symbolisch!) differenziert werden. (Falls ich da was übersehen habe, einfach motzen ;))

Nene ich glaub du hast das genau richtig verstanden.
Also ich muss ja erstmal einen Algorithmus entwickeln, der das Überhaupt berechnet. Also das ganze Antlr zeug spielt erstmal keine Rolle.

Ich muss ja irgendeine Klasse Function haben. Die muss ja irgendwelche Attribute haben.
Also zB Term oder so.

Wenn ich jetzt einen String habe „f(x)=x^2“, dann kann ich von mir aus eine Function erstellen und den String unter dem Attribut speichern.
wenn ich dann die „double differenziere(Function f, double x)“ aufrufe mit eben jener Funktion, dann muss ich ja genau wie du gesagt hast, die Steigung an der Stelle x=2 im prinzip zurückgeben.
Nehmen wir an ich rechne mit dem Differenzenquotienten erstmal. Also (f(x1)-f(x0))/(x1-x0), dann muss ich ja irgendwie das x in meinem Funktionsobjekt ersetzen und damit rechnen. Im Moment hab ich ja nur einen String.

Es hat wohl irgendwas mit dem Überladen des ()-Operators aufsich, aber keine Ahnung wie das zusammenhängt. Vllt bin ich auch einfach nur zu blöd und sehe den Wald vor lauter Bäumen nicht :stuck_out_tongue_winking_eye:

Vielleicht, ja (aber vielleicht hab’ ICH auch was falsch verstanden). Ich würde (ohne die Aufgabenstellung jetzt nochmal gegengelesen zu haben) davon ausgehen, dass man, wenn man z.B. die Funktion f(x) = sin(x^2) dort differenzieren will, man den Term eben NICHT als String vorliegen hat. In der Java-Welt würde ich davon ausgehen, dass es dann sowas gibt wie

interface Function {
    double evaluate(double x);
}

und man dann schlicht aufrufen will

Differentiator.differentiate(new Function() {
    @Override
    public double evaluate(double x) {
        return Math.sin(x*x);
    }
});

In C++ geht das recht analog (in C++11 sogar mit Lambdas), aber… es gibt dabei (soweit ICH das verstehe) weder einen “Zustand” (im Sinne von Atributen des Function-Objekts), noch einen String, der einen Term speichert…