Usereingabe auswerten
heutemalunbekannt
- javascript
0 molily
So, da bin ich mal wieder...
...und ich bin dabei, ein Javascript Formular zu erstellen, mit dem der Benutzer anhand des Newton Verfahrens eine Nullstelle einer ganzrationalen Funktion xten Grades nährungsweise bestimmten lassen kann. Probleme bereitet mir dabei die Eingabe des Users.
Bisher sieht das ganze so aus
Dabei ist der Benutzer allerdings in seinen Eingabemöglichkeiten stark eingeschränkt.
Ich wollte daher eine Eingabe realisieren, bei der der Benutzer einfach die Formel eingibt und das Programm selbstständig die Werte ausliest.
Beispieleingabe: x^9 - x^6 + 4x^3 + 1,5x^4 -99
Meine Ideen waren zuersteinmal folgende:
Danach sollte dann das auswerten das Auswerten kommen. Eine Möglichkeit wäre es vielleicht, die Gleichung per eval() auszurechnen, nachdem man zuvor die x durch entsprechende Zahlen ersetzt hat, aber eval() ist laut wahsaga evil(), weshalb man es nicht benutzen solle.
Leider fehlen mir die Ideen, wie ich sonst an die Sache rangehen könnte. Hat jemand von euch Vorschläge? Gibt es vielleicht schon Klassen für soetwas?
Hallo,
Wenn du Terme ausrechnen willst, ist eval() schon okay, das Problem ist eher, dass eval() JavaScript-Expressions, also JavaScript-Code ausrechnen kann, mehr aber nicht. Da hast du also nur die paar primitiven Operatoren von JavaScript zur Verfügung, und z.B. Potenzen werden in JavaScript nicht über einen Operator, sondern über eine Methode des Math-Objektes durchgeführt. Die Formel zu normalisieren ist wahrscheinlich die einfachste Aufgabe, da sehe ich keine nennenswerten Schwierigkeiten. Aber das Ausrechnen geht beileibe nicht mit einfach mit eval() bzw. es wird ein größerer Aufwand sein, aus der Formel eine gültige JavaScript-Expression zu machen, die du dann getrost an eval() verfüttern kannst - "1,5x^4" bei x = 5 wird etwa zu eval("1,5 * Math.pow(5, 4)") usw. Dann musst du natürlich die Operatorenrangfolge beachten, aber die dürfte den üblichen Rechenregeln entsprechen. (Mit ganz viel Aufwand kann man sicher auch ohne Expressions und eval arbeiten, ich sehe hier aber keien nennenswerten Vorteil.)
Mathias
Hallo, (...)
Mathias
Hallo Mathias :)
Danke erstmal, dass du geschrieben hast.
Ich habe deinen Ratschlag befolgt und es bereits soweit geschafft, dass ich eine Eingabe wie "x^3,2 + -5,2x^2 - 4:2" in "Math.pow(x, 3.2)-5.2*Math.pow(x, 2)-4/2" umzwandeln und dann mit eval() ausrechnen zu lassen.
Für das Newton Verfahren muss ich aber noch einen Schritt weiter gehen und von obiger Formel die Ableitung bilden.
Sprich, aus:
3*x^5 + 3*x^4 - 5*x + 3
soll werden
5*3*x^(5-1) + 4*3*x^(4-1) - 5
oder einfacher:
15*x^4 + 12*x^3 - 5
Dazu überlegt habe ich mir, einfach alle a*x^b per Regex herauszusuchen und mit backreferences durch b*a*x^(b-1) zu ersetzen. Das Problem ist nun, dass ich mit $i nicht arbeiten kann.
Beispielzeichenkette: "5x2"
Regex: replace(/ ([0-9]) x ([0-9]) /g, "$1 x $2") <- funktioniert, Leerzeichen nur zur besseren Übersicht
Regex: replace(/ ([0-9]) x ([0-9]) /g, "" + ($1 * $2) + "x $2") <- funktioniert nicht, $1 ist natürlich keine Variable.
Wie kann ich also mit $1, $2 usw. rechnen?
Ergänzung:
Zeichenkette: x^4
replace(/x^([0-9])/g, "x^" + (parseInt("$1") + 1) + "");
Ergibt: x^NaN
Wieso not a number?
Hallo,
replace(/x^([0-9])/g, "x^" + (parseInt("$1") + 1) + "");
Du musst dir vorstellen, wie der JavaScript-Parser und -Interpreter arbeitet: Erstmal wertet er die Expressions aus und führt erst dann den Befehl mit den angegebenen Parametern aus. Und der replace-Parameter ist ein einfacher String und keine Expression, die dann erst innerhalb von replace ausgeführt wird!
Hier haben wir die Expression »"x^" + (parseInt("$1") + 1) + ""«, die erstmal so berechnet wird:
"x^" + (parseInt("$1") + 1) + ""
= "x^" + (NaN + 1) + ""
= "x^" + NaN + ""
= "x^" + NaN.toString() + ""
= "x^" + "NaN" + ""
= "x^NaN"
Dann wird replace(... , "x^NaN") aufgerufen. Das ist alles, was replace zu Gesicht bekommt. Erst damit arbeitet replace und ersetzt $1 ggf. durch etwas. Da kommt aber gar kein $1 mehr vor.
Mathias
Hallo,
Mathias
Danke für die Aufklärung, Mathias.
Mit deinem Vorschlag, eine Funktion zu verwenden, funktioniert das ganze wunderbar. Ich stehe aber schon wieder vor einem weiteren Problem ;) (viele sind es nicht mehr), das vermutlich wieder mit dem genauen Vorgehen von Javascript (des Interpreters) zu tun hat. (Leerzeichen nur zur besseren Übersicht)
Teststring: "0 + x^2 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0"
replace(/[+-][0-9]+([+-])/g, "$1");
Ich nahm an, es würde dort nun herauskommen:
"0 + x^2 + 0" aber weit gefehlt, es kommt heraus: "0 + 2*x^1 + 2 + 4 + 6 + 8 + 0"
Ich hatte mir gedacht, dass der Parser(richtig?) den String durchgeht und nach Zahlen sucht, vor denen und nach denen ein Plus oder Minus steht. Findet er eine solche, ersetzt er die Zahl und das Plus/Minus vor der Zahl durch nix (löscht sie also).
Zuerst findet er die 1 und löscht sie mitsamt des Plus' vor der Zahl. Nun steht da "0 + x^2 +v 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0", aber anscheinend geht er jetzt hinter das Plus, was hinter der 1 stand (bei v) und dann steht natürlich kein Plus mehr vor der 2. Somit überspringt er jede zweite Zahl. Ist meine Vermutung richtig? Und viel wichtiger: was soll ich jetzt tun, damit er das nicht tut?
Ist meine Vermutung richtig? Und viel wichtiger: was soll ich jetzt >> tun, damit er das nicht tut?
Ich habe nun selbst herausgefunden, dass meine Vermutung richtig war. Das Problem habe ich jetzt so gelöst, dass ich teste, ob der entsprechende Regex passt und ihn (falls ja) so lange durchlaufen lasse, bis kein [+-][0-9][+-] mehr übrig ist.
Noch eine Frage brennt mir aber auf dem Herzen. Gibt es eine Funktion wie eval(), die einen Ausdruck ausrechnet, aber nur die Teile, die sie kann (und dann alle anderen so lässt)?
Beispiel: eval2("x^2 + 5 + 7 * 3")
ergibt: "x^2" + 5 + 21 ergibt: "x^2" + 26 ergibt: "x^2+26" oder "x^2 + 26"?
Hallo,
Gibt es eine Funktion wie eval(), die einen Ausdruck ausrechnet, aber nur die Teile, die sie kann (und dann alle anderen so lässt)?
Nein. Es sei denn, du schreibst dir selbst eine entsprechende Logik - aber da müsste man einen Parser und einen Interpreter implementieren, der die gängigen arithmetischen Regeln umsetzt. Ohne Mathematik- und Informatik-Studium kann sowas leicht ausufern. ;)
Mathias
Hallo,
Regex: replace(/ ([0-9]) x ([0-9]) /g, "" + ($1 * $2) + "x $2") <- funktioniert nicht, $1 ist natürlich keine Variable.
Das geht so nicht.
Da musst du mit einer Ersetzungsfunktion arbeiten, die die gefundenen Subpattern als Parameter übergeben bekommt:
function ersetzungsfunktion (str, a, b) {
return (b * a) + " * x ^ " + (b - 1);
}
var teststring = "15*x^4";
var newstring = teststring.replace(/(-?\d+)*\s*\*\s*x\s*\^\s*(\d+)/ig, ersetzungsfunktion);
document.write("<p>" + newstring + "</p>");
Diese Vorgehensweise ist ein bisschen unüblich und wenig bekannt, aber für solche Fälle ideal.
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:String:replace#Specifying_a_function_as_a_parameter
Mathias