Hallo Besucher, der Thread wurde 1,7k mal aufgerufen und enthält 18 Antworten

letzter Beitrag von Soldier am

Wie eine mathematische Funktion in ein laufendes Basic Programm einbinden?

  • Hallo zusammen,


    ich hab mal ne Frage. Und zwar wollte ich einen kleinen Wertetabellen Rechner schreiben. Dazu wird der Benutzer aufgefordert, eine Funktion einzugeben, bspw. "X^2". Dann wird noch gefragt, von wo bis wo das X liegen soll. Jetzt weiss ich nur nicht, wie ich die eingegebene Formel zur Berechnung in das Basic Programm einfliessen kann. Hatte vor, bspw in einer For...Next Schleife sowas wie "Z={Funktion}", weiss halt nicht, wie ich die vom Benutzer eingegebene Funktion nutzen kann...


    Gruß
    Soldier

  • Sofern es dafür einen bestimmten Trick geben sollte, würde ich mich auch freuen, ihn zu hören.


    Ich sehe letztlich nur folgende zwei Möglichkeiten:


    1. Du verzichtest darauf, die Funktion ins laufende Basic-Programm einzubinden. Stattdessen weist du am Anfang des Programms darauf hin, man habe als Benutzer selbst dafür zu sorgen, dass in einem Unterprogramm (z.B. "ab Zeile 3000") die Funktion steht, und falls das noch nicht der Fall ist, soll man doch bitte das Programm mit RUN/STOP unterbrechen um es nachzuholen (oder du baust eine Ja/Nein-Frage ein, die das Programm unterbricht). Habe bereits einige Beispielprogramme gesehen (z.B. im Buch "32 BASIC-Programme für den C64"), die es einfach so handhaben.
    Man kann dann z.B. in Zeile 3999 schon das RETURN setzen, dann sollten dem Benutzer ja mehr als genug Zeilen zur Verfügung stehen, um die Funktion zu definieren, selbst wenn er kompliziertere Sachen machen möchte, die sich nicht nur durch eine einfache Formel ausdrücken lässt (z.B. mit Fallunterscheidung für verschiedene Wertebereiche).
    Der Nachteil ist dabei natürlich, dass das nicht gerade benutzerfreundlich ist, noch dazu anfällig für Fehler (z.B. Tippfehler, mangelnde BASIC-Kenntnisse des Benutzers, bewusste Eingabe von Blödsinn, ...)



    2. Du bastelst einen kompletten Parser für mathematische Funktionen mit in das Programm, oder zumindest einen, der mit all jenen Funktionen zurechtkommt, welche zu erwarten wären, dass der Benutzer sie verwenden möchte. Mit anderen Worten, du "bringst deinen Programm bei", wie es vom Benutzer eingegebenen "lesen" muss.
    Hierbei lassen sich Fehler vom Anwender dann auch gleich mit abfangen (sofern man an alle schwachsinnigen Ideen, auf die er kommen könnte, denkt ;))
    Hier ist der Nachteil, dass dies im Grunde ein eigenes Projekt für sich ist, sprich vermutlich aufwändiger wird, als das komplette restliche Programm, also was die Programmierarbeit angeht, auch das Testen und Debuggen, und natürlich auch den Speicherplatz den dann das komplette fertige Programm erfordert.



    Also, es kann sein, dass es vielleicht einen Trick gibt, der so aussehen könnte, dass man während der Laufzeit den BASIC-Code im Speicher verändert, aber auf Anhieb wüsste ich es nicht. Falls jemand so einen Trick kennt, wäre ich wie gesagt ebenfalls dankbar, denn ich hab mich selbst schon über dieses "Problem" geärgert.

  • Es gibt einen ganz einfachen Weg: Starte den 'ZX Spectrum Emulator'. Sinclair BASIC kann, anders als die meisten adneren Dialekte, mit VAL(a$) ganze Formeln berechnen und nicht nur einzelne Zahlen aus dem String herausziehen.


    Natürlich sollte es möglich sein, sich eine Maschinencode-Routine zu schrieben, die auf USR(a$) den String an den Formel-Evaluator übergibt... /müßte/ ganz einfach sein, /müßte/ nur mal jemand machen... vermutlich hat es sogar schon jemand gemacht, dann /müßte/ man es nur noch finden. En /müßte/-sches Projekt, wie man sieht.

  • Macht es doch nicht kompliziert. Du machst ein selbst-modifizierendes Basic-Programm. Schreib eine fertige Basic-Zeile mit der eingegebenen Formel als DEF FN(x), poke genug returns in den Tastaturpuffer und ab gehts.


    Ist natürlich doof, wenn es dann einen Syntax Error oder Ähnliches gibt ;)

  • Im 64ér tips und trick steht etwas zu selbstmodifizierten basic programmen.
    Das könnte hier helfen.
    Soweit ich weiss, wird zuerst der bildschirm gelöscht und es werden via programm die betreffenden zeilen ausgegeben.
    Danach werden returns in den tastaturpuffer geschrieben und das programm kurzzeitig beendet und dann wieder (automatisch) gestartet.


    Klingt jetzt recht kompliziert, ist es aber nicht. Wenn Du willst, schicke ich dir das entsprechende Kapitel mal zu.


    Gruß C-Man

  • Am sinnvollsten waere vielleicht folgendes:
    den String mit der Funktion auf gueltigkeit parsen.
    Also pruefen ob das Schema Zahl, gueltiger Operator, Zahl, ... passt.
    Das koennte ein wenig komplex werden (mit Klammern, etc).
    Dann das ganze in blau auf blau auf den Schirm schreiben als BASIC Zeile und wie beschrieben ueber den Tastaturpuffer eingeben.
    Das parsen vorweg soll verhindern dass unguelitger Quatsch in der definition steht "X=4%^&^G%ghggg" oder so. : )
    Alternativ liesse sich die Adresse des aktuellen Bildschirms mit ganz wenigen Pokes von $0400 nach $c000 verschieben fuer diese Aktion.
    Dann muss man nichts loeschen oder so etwas.

  • An ein selbstmodifizierendes Basic-Programm hatte ich auch sofort gedacht, aber das fängt natürlich keinen Syntax error ab. Gibt es evtl. ne Möglichkeit wie man mit einer Rom-Routine die Syntax checken kann? Oder kann man den Vektor für die Ausgabe von "?SYNTAX ERROR" verbiegen und durch ein "GOSUB 1000" ersetzen, wobei man in 1000 zur Überprüfung der Funktion auffordert? Das würde ne Menge Programmierarbeit ersparen.


    Jens

  • Hm, also ich hatte auch vor, dass in eine Bildzeile zu schreiben und dann durch Return zu ner Basic Zeile zu machen. Hatte dazu folgenden Code (vereinfacht):


    Code
    1. 10 INPUT"FUNKTION";A$
    2. [...]
    3. 50 PRINT"60 Y=";A$;CHR$(13)
    4. [...]


    Hat aber nicht so ganz funktioniert, die Zeile 60 stand da zwar auf dem Bildschirm, wurde jedoch nicht in das Basic Programm übernommen...


    Commodore Man: Könntest du mir das Kapitel mal zu schicken, würde mich echt interessieren.

  • Du musst das Basic-Programm natuerlich verlassen.
    Den Tastaturpuffer dann auch direkt anpoken vorher.
    Also nach dem

    Code
    1. 60 Y=A$


    eine Zeile um den Cursor genau dahinter zu setzen.
    Ausserdem ein

    Code
    1. GOTO 10

    oder so vorbereiten.
    Dann inden Puffer ab

    Code
    1. 631

    die passenden RETURNs poken (13) und angeben wieviele Tastendruecke im Puffer liegen (an

    Code
    1. 198

    )

  • Die Fehlerabfrage könnte man eigentlich auch den Basic-Interpreter im Direktmodus machen lassen:

    Code
    1. input"funktion";f$:print"{clr}y="f$:print"{2xdown}goto4":print"goto3"
    2. poke631,19:poke632,13:poke633,13:poke198,3:end
    3. print"{3xdown}funktion kaputt!":goto1
    4. print"{clr}5 y="f$":return":print"goto6":goto2
    5. :
    6. input"{clr}von, bis";x0,x1
    7. forx=x0tox1:gosub5:printy:next
  • Okay, meine Idee funktioniert nur teilweise, der Interpreter hat glaub ich ne Macke. Oft kommen zu den geraden Zahlen 0.000001 oder 0.000002 hinzu. Ich hab bspw. noch eine Step Funktion eingebaut, wenn ich da Step 0.1 eingebe, nimmt der iwann Werte wie X=53.899999 oder 19.000001.... Dann kommen natürlich für Y falsche Werte raus. Beispiel:


    Funktion: X^3-X^2
    Von 1 - 100
    Step 0.1


    65.8999983 = 281848.348


    Richtig wäre aber:
    65.9 = 281848.369


    Gibt es da irgendeinen Trick, das zu runden bevor es ausgerechnet wird?


    Gruß
    Soldier

  • Das ist mir auch schonmal aufgefallen...
    Es gibt ja die INT()-Funktion, aber selbst die gibt einem manchmal kackendreist Sachen mit ...9999 oder ...0001 aus... Du kannst es allerdings auch einer Integer-Variable zuweisen (variablenname%), dann werden in jedem Fall jegliche Nachkommastellen abgeschnitten.


    Willst du aber z.B. auf 4 Nachkommastellen runden musst du deine Zahl halt zuerst mal 10000 nehmen, dann durch die %-Variable schleusen, wieder zurück in eine Fließkomma, und dann wieder durch 10000.



    Bezüglich der Sache mit FOR und STEP könnt ich mir nur denken, dass du vielleicht auf STEP verzichtest, sprich ganz Schritte machst, aber dann in der Schleife selbst die Zahlen so interpretierst, dass die gewünschte Schrittweite vorkommt (also z.B. durch 10 teilen)...


    (Warum die FOR-Schleife keine Integer-Variablen annimmt weiß wohl auch nur der Entwickler des Interpreters von damals...)

  • Tja, willkommen in der Welt der Programmierer :)
    Float-Zahlen kann man technisch bedingt einfach nur begrenzt genau darstellen. Einige relativ gradlinige Werte kann man noch nicht mal damit darstellen. Dadurch kommen bei längeren Rechenketten dann einfach Ungenauigkeiten rein.


    Da hilft eventuell als Zählvariable ein Int benutzen und dann den Float-Wert für jeden Step direkt ausrechnen.

  • Hab mir jetzt nen kleinen "Runden" Algortihmus gebaut^^ Der funktioniert wunderbar, den muss ich jetzt nur noch in mein Programm basteln.


    Der Algorithmus sieht so aus (ja, kompliziert, aber funktioniert :) )



    Werde das wiegesagt später mal in mein Programm umsetzen.


    Gruß
    Soldier