Gleichung erstellen
lima-city → Forum → Programmiersprachen → PHP, MySQL & .htaccess
baum
berechnen
blatt
code
dank
ergebnis
erzeugen
gleichung
http
null
operation
rand
schritt
setzen
switch
text
url
zahl
zeichen
zufallsgenerator
-
Ja, ich habe da so ein Problem und da würde ich gerne wissen, wie erstelle ich eine Gleichung, die durch ein =-Zeichen getrennt ist, aber jetzt nicht einfach so was hier ist: 4+4=8
Sondern sowas: 4*(4-8)²+65=-223,5*2
Wie kann ich sowas erstellen, als Zufallsgenerator????
Wenn das Niemand wissen sollte kann man mir auch gerne erst einmal einen Zufallsgenerator für Gleichungen wie: 4+4=8 geben!!! -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Hallo carl-schoeneich,
die längere Gleichung ist gar keine sondern (Quotientenmengen mal ausgeschlossen) schlicht falsch.
Das '=-' ist ja eigentlich auch kein Zeichen sondern ein '=' gefolgt von einer negativen Zahl.
Wenn Du einen mathematische Ausdruck (nur die linke oder rechte Seite) per Zufallsgenerator erzeugen willst, dann geht das wie folgt:
Als erstes musst Du die erlaubten mathematischen Operationen mit Zahlen assoziieren. Z.B. folgendermaßen:
1 => + 2 => - 3 => * 4 => / 5 => Potenzieren (x^y)
Als zweites benötigst Du einen binären Baum dessen Elemente entweder eine mathematische Operation (innerer Knoten) oder eine Zahl (Blatt) darstellen.
Jetzt kannst Du wie folgt vorgehen:
Wenn alle Kindknoten mit Zahlen besetzt sind, dann ist man fertig. Man sollte aber ab einer bestimmten Baumtiefe das setzen von Zahlen erzwingen, d.h. (3) und (5) werden nicht durchgeführt und nur noch eine Zufallszahl erzeugt, damit das nicht ewig weitergeht.1. Erzeuge eine ganzzahlige Zufallszahl zwischen 1 und 5 2. Füge die zugehörige Operation in den Baum ein. 3. Erzeuge eine ganzzahlige Zufallszahl zwischen 1 und 2 für den ersten Kindknoten 4. Wenn die Zufallszahl 1 ist, dann für den ersten Kindknoten weiter bei (1.) sonst erzeuge eine Zahl und füge sie ein. 5. Erzeuge eine ganzzahlige Zufallszahl zwischen 1 und 2 für den zweiten Kindknoten 6. Wenn die Zufallszahl 1 ist, dann für den zweiten Kindknoten weiter bei (1.) sonst erzeuge eine Zahl und füge sie ein.
Am Ende hat man dann z.B. sowas:
Diesen Daum kann man jetzt der Reihe nach in eine Formel umbauen, indem man rekursiv absteigt bis man bei einem Blatt (Zahl) ist und dann Schritt für Schritt wieder aufsteigt.. + ___________|___________ | | * ^ ___|___ ___|___ | | | | 8 + 3 2 ___|___ | | 3 4
Zusammengesetzt kommt dann (Klammern gemäß Operatorpräzedenz einfügen) folgendes raus:
8*(3+4)+3^2
Edit: Hier habe ich noch etwas Beispiel-Code für Binary-Trees in PHP gefunden:
http://www.zend.com//code/codex.php?ozid=539&single=1
Beitrag zuletzt geändert: 9.3.2012 22:31:43 von darkpandemic -
Ja, danke für diese sehr ausführliche Erklärung!!!
Mal sehen, wie sich das umsetzen lässt!!!
Doch, mein eigentlich größtes Problem ist, wie erstelle ich dann zu dieser Seite der Gleichung die andere Seite, die den Gleichen Wert hat????
Beitrag zuletzt geändert: 10.3.2012 8:40:02 von carl-schoeneich -
Hallo carl-schoeneich,
ich habe mir mal erlaubt die Sache ein wenig anzuprogrammieren:
Und mir ist dabei auch noch eingefallen, wie Du die zweite Seite bekommen kannst.<?php class Operation { const Add = 0; const Sub = 1; const Mul = 2; const Div = 3; const Pow = 4; const MaxIndex = 4; } class Node { public $firstChild = NULL; public $secondChild = NULL; public $value = 0; function isOperator() { return !is_null($this->firstChild) && !is_null($this->secondChild); } function getValue() { if($this->isOperator()) { switch($this->value) { case Operation::Add: return $this->firstChild->getValue() + $this->secondChild->getValue(); case Operation::Sub: return $this->firstChild->getValue() - $this->secondChild->getValue(); case Operation::Mul: return $this->firstChild->getValue() * $this->secondChild->getValue(); case Operation::Div: return $this->firstChild->getValue() / $this->secondChild->getValue(); case Operation::Pow: return pow( $this->firstChild->getValue(), $this->secondChild->getValue()); default; return 0; } } else { return $this->value; } } function getString() { if($this->isOperator()) { switch($this->value) { case Operation::Add: { $text = $this->firstChild->getString(); if($this->secondChild->isOperator()) { $text .= "+(" . $this->secondChild->getString() . ")"; } else if($this->secondChild->value < 0) { $text .= $this->secondChild->getString(); } else { $text .= "+" . $this->secondChild->getString(); } return $text; } case Operation::Sub: { $text = $this->firstChild->getString(); if($this->secondChild->isOperator()) { $text .= "-(" . $this->secondChild->getString() . ")"; } else if($this->secondChild->value < 0) { $text .= "+" . (-$this->secondChild->getValue()); } else { $text .= "-" . $this->secondChild->getString(); } return $text; } case Operation::Mul: { $text = ""; if( $this->firstChild->isOperator() || $this->firstChild->value < 0) { $text .= "(" . $this->firstChild->getString() . ")"; } else { $text .= $this->firstChild->getString(); } $text .= "*"; if( $this->secondChild->isOperator() || $this->secondChild->value < 0) { $text .= "(" . $this->secondChild->getString() . ")"; } else { $text .= $this->secondChild->getString(); } return $text; } case Operation::Div: { $text = ""; if( $this->firstChild->isOperator() || $this->firstChild->value < 0) { $text .= "(" . $this->firstChild->getString() . ")"; } else { $text .= $this->firstChild->getString(); } $text .= "/"; if( $this->secondChild->isOperator() || $this->secondChild->value < 0) { $text .= "(" . $this->secondChild->getString() . ")"; } else { $text .= $this->secondChild->getString(); } return $text; } case Operation::Pow: { $text = ""; if( $this->firstChild->isOperator() || $this->firstChild->value < 0) { $text .= "(" . $this->firstChild->getString() . ")"; } else { $text .= $this->firstChild->getString(); } $text .= "^"; if( $this->secondChild->isOperator() || $this->secondChild->value < 0) { $text .= "(" . $this->secondChild->getString() . ")"; } else { $text .= $this->secondChild->getString(); } return $text; } default; return 0; } } else { return $this->value; } } } function buildTreeRecursion($maxDepth) { $node = new Node(); if($maxDepth > 0 && rand(0,1) == 0) { $node->firstChild = buildTreeRecursion($maxDepth-1); $node->secondChild = buildTreeRecursion($maxDepth-1); $node->value = rand(0,Operation::MaxIndex); } else { $node->value = rand(-20, 20); } return $node; } function buildTree($maxDepth) { $tree = new Node(); $tree->value = rand(0,Operation::MaxIndex); $tree->firstChild = buildTreeRecursion($maxDepth-1); $tree->secondChild = buildTreeRecursion($maxDepth-1); return $tree; } srand(); $tree = buildTree(3); echo $tree->getString(). "=" . $tree->getValue(); ?>
Du kannst den Wurzelknoten standardmäßig auf eine Addition setzen. Dann hast Du als Ergebnis ja immer etwas von der Form
Andererseits kannst Du ja den gesamten Baum berechnen lassen, d.h. Du weißt was insgesamt herauskommt. Dann kannst Du die Sache einfach umstellen zu:<linker Teilbaum> + <rechter Teilbaum>
Und schon hast Du was Du willst<linker Teilbaum> = <Gesamtergebnis> - (<rechter Teilbaum>)
-
Danke!!!
Das klappt alles super!!!
Aber kann man das auch noch irgendwie begrenzen, dass das Ergebnis nicht über 10000 sein sollte, oder so???
Wäre sehr hilfreich!!!
Aber nochmal schonmal VIELEN DANK!!!!!! -
Hallo carl-schoeneich,
das einfachste Vorgehen um das Ergebnis einzuschränken besteht darin, einfach einen neuen Baum zu generieren wenn der aktuelle außerhalb des gewünschten Intervalles liegt.
Allerdings kann kann man auch vorab schon die erlaubten Divisoren und Exponenten einschränken, damit allzu große Werte unwahrscheinlicher werden (und damit kein NAN/INF vorkommt):
Zusätzlich habe ich noch an der Wahrscheinlichkeit zum Setzen einer Zahl gedreht, damit man interessantere Ergebnisse bekommt.function buildTreeRecursion($maxDepth) { $node = new Node(); if($maxDepth > 0 && rand(0,2) != 0) { $node->value = rand(0,Operation::MaxIndex); if($node->value == Operation::Div) { $node->firstChild = buildTreeRecursion($maxDepth-1); do { $node->secondChild = buildTreeRecursion($maxDepth-1); }while(abs($node->secondChild->getValue()) < 0.0001); } else if($node->value == Operation::Pow) { do { $node->firstChild = buildTreeRecursion($maxDepth-1); }while($node->firstChild->getValue() < 0); do { $node->secondChild = buildTreeRecursion($maxDepth-1); }while(abs($node->secondChild->getValue()) > 5); } else { $node->firstChild = buildTreeRecursion($maxDepth-1); $node->secondChild = buildTreeRecursion($maxDepth-1); } } else { $node->value = rand(-20, 20); } return $node; } function buildTree($maxDepth) { $tree = new Node(); do { $tree->value = 0; $tree->firstChild = buildTreeRecursion($maxDepth-1); $tree->secondChild = buildTreeRecursion($maxDepth-1); } while(abs($tree->getValue()) > 10000); return $tree; } $tree = buildTree(4); echo $tree->getString() . "=" . $tree->getValue() ."<br/>"; echo $tree->firstChild->getString() . "="; echo $tree->getValue() . "-("; echo $tree->secondChild->getString(). ")";
In der Node-Klasse sind im übrigen noch zwei kleine Vertipper: In den switch-Anweisungen gehört nach 'default' ein ':' (Doppelpunkt) und kein ';' (Strichpunkt). -
Wo soll ich das jetzt einsetzen?????
Aber sonst vielen Dank, damit müsste dann alles klappen!!!! -
Hallo carl-schoeneich,
die Klassen 'Operation' und 'Node' läßt Du wie sie sind.
Die bisherigen Funktionen 'function buildTree($maxDepth)' und 'function buildTreeRecursion($maxDepth)' löscht Du raus und kopierst dafür die geänderten Versionen rein.
Die letzen 6 Zeilen erzeugen nur eine Beispielausgabe, die sind nicht wichtig. -
OK, danke!!!!!!!!
Funktioniert alles wie geplant!
Nur noch eins, wie kann ich das endgültige Ergebnis der Gleichung dann ausgeben??
Also dann, dass beide Seiten diesen Wert haben???
Also einfach nur -6 oder so?
Beitrag zuletzt geändert: 16.3.2012 20:06:44 von carl-schoeneich -
Hallo carl-schoeneich,
wenn Du die Gleichung nach dem Schema
ausgibst, dann ist der Wert der linken Seite der Gleichung gleich dem Wert des linken Teilbaumes. (Linker Teilbaum soll der erste Kinknoten = firstChild sein).<linker Teilbaum> = <Gesamtergebnis>-(<rechter Teilbaum>)
Diesen bekommst Du mit
Die Knoten sind ja so gemacht, dass man mit getValue() den numerischen Wert und mit getString() den mathematischen Ausdruck bekommt. Die rechte Seite der Gleichung hat natürlich den gleichen Wert. Wenn man es explizit gegengerechnet haben will, dann kann man das wie folgt berechnen:$leftValue = $tree->firstChild->getValue();
$rightValue = $tree->getValue() - $tree->secondChild->getValue();
-
Danke!
Damit funktioniert jetzt echt alles!!!! -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage