Seite 1 von 1
Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 15:45
von argus
Liebe Foristen,
ich habe folgendes Problem:
eine kleine Prozedur, die rekursiv eine Summe errechnen soll, funktioniert einwandfrei bis zum 8. Summanden, liefert aber beim 9. Summanden das Ergebnis NaN. Coding:
Code: Alles auswählen
Procedure.d summe(exp$)
trm$=StringField(exp$,1,"+")
exp$=RemoveString(exp$,trm$,#PB_String_CaseSensitive,1,1)
If exp$=""
ProcedureReturn ValD(trm$)
Else
exp$=RemoveString(exp$,"+",#PB_String_CaseSensitive,1,1)
ProcedureReturn ValD(trm$)+summe(exp$)
EndIf
EndProcedure
Der Aufruf mit
liefert das Ergebnis 28.0
Der Aufruf mit
liefert dagegen das Ergebnis NaN.
Laut Help sind rekursive Prozedurenaufrufe aber möglich:
"In PureBasic wird bei Prozeduren die Rekursion voll unterstützt, jede Prozedur kann sich auch selbst aufrufen."
Hat jemand eine Idee woran das liegen könnte, dass die Prozedur beim 9. Summanden NaN liefert?
Viele Grüße von
Argus
Re: Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 16:17
von NicTheQuick
Ja, die Begrenzung gibt es sogar schon immer. Purebasic versucht schlau zu sein und will alle "Double"-Register ausnutzen, die es in der CPU gibt, anstatt die Werte auf den Stack zu schieben. Das sind nun mal nicht mehr als 8 Register, also kommt dieser Fehler.
So oder so ähnlich hab ich es mal verstanden. Bin leider nicht so sehr in dem ASM-Thema drin. Um das zu umgehen, muss man ganz schön tricksen.
Aber bevor ich dir da jetzt was zusammenbastel, würde ich vorschlagen die Procedure iterativ statt rekursiv zu bauen.
Re: Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 16:28
von argus
Danke NicTheQuick,
das ist natürlich nicht so schön. Darauf hätten die Macher von PB wenigstens im Handbuch hinweisen können. Das verstehe ich nicht unter voller Unterstützung von Rekursivität.
Gib mir bitte mal einen Tipp bezüglich Iteration. Hast du da ein Beispiel?
Viele Grüße von
Argus
Re: Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 16:41
von Nino
argus hat geschrieben:Der Aufruf mit
liefert das Ergebnis 28.0
Das richtige Ergebnis ist übrigens 36.
argus hat geschrieben:Gib mir bitte mal einen Tipp bezüglich Iteration. Hast du da ein Beispiel?
Ich bin zwar nicht NicTheQuick, aber hier ist ein Beispiel für ein iteratives Vorgehen:
Code: Alles auswählen
EnableExplicit
Procedure.d Summe(expr$)
Protected.i summanden, i
Protected.d ergebnis = 0
summanden = CountString(expr$, "+") + 1
For i = 1 To summanden
ergebnis + ValD(StringField(expr$, i, "+"))
Next
ProcedureReturn ergebnis
EndProcedure
Debug Summe("1+2+3+4+5+6+7+8+9") ; zeigt richtigerweise 45.0
Du hast es dir unnötig kompliziert gemacht.
Rekursion sollte man nur einsetzen wo es nötig ist. Das ist hier nicht der Fall.
Re: Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 17:21
von argus
Hallo Nino,
ok, das Ergebnis war bei mir auch 36 ... hatte fälschlicherweise 28 angegeben.
Ja ok, das iterative Vorgehen ist eine Möglichkeit. Der Vorteil bei der Rekursion ist aber, dass man sich die Schleifenstruktur spart. Ich wollte die Rekursion nutzen, um einen Parser zu schreiben, der mir einen arithmetischen Ausdruck berechnet, der als String eingegeben wird wie z.B 2+3+7*(17-1,7+2^(3+2*3))*sin(45) ...
VG von
Argus
Re: Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 17:34
von Nino
argus hat geschrieben:Der Vorteil bei der Rekursion ist aber, dass man sich die Schleifenstruktur spart.
Das ist kein Vorteil, da wird nichts "gespart".
So wie du es gemacht hast, steht es in Lehrbüchern als Beispiel dafür, wie man
nicht programmieren sollte
(ist nicht böse, allerdings völlig ernst gemeint).
Re: Problem beim rekursiven Prozedur-Aufruf
Verfasst: 27.07.2017 18:44
von GPI
argus hat geschrieben:Ja ok, das iterative Vorgehen ist eine Möglichkeit. Der Vorteil bei der Rekursion ist aber, dass man sich die Schleifenstruktur spart.
Dafür wird der Stack zugespamt etc. Die iterative Methode dürfte auch deutlich schneller sein.
Es wurden auch einige Codes geschrieben und hier veröffentlicht, um Berechnungen durchzuführen. (bspw. meins:
https://github.com/SicroAtGit/PureBasic ... h/Eval.pbi )
Ich würde allerdings mittlerweile einfach LUA einbinden. Damit kann man auch solche Berechnungen durchführen, hat aber noch deutlich mehr Möglichkeiten.