Problem beim rekursiven Prozedur-Aufruf

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
argus
Beiträge: 18
Registriert: 24.02.2014 12:12

Problem beim rekursiven Prozedur-Aufruf

Beitrag 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

Code: Alles auswählen

lin$="1+2+3+4+5+6+7+8"
Debug summe(lin$)
liefert das Ergebnis 28.0

Der Aufruf mit

Code: Alles auswählen

lin$="1+2+3+4+5+6+7+8+9"
Debug summe(lin$)
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
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8679
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Problem beim rekursiven Prozedur-Aufruf

Beitrag 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.
Bild
Benutzeravatar
argus
Beiträge: 18
Registriert: 24.02.2014 12:12

Re: Problem beim rekursiven Prozedur-Aufruf

Beitrag 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
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Problem beim rekursiven Prozedur-Aufruf

Beitrag von Nino »

argus hat geschrieben:Der Aufruf mit

Code: Alles auswählen

lin$="1+2+3+4+5+6+7+8"
Debug summe(lin$)
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.
Benutzeravatar
argus
Beiträge: 18
Registriert: 24.02.2014 12:12

Re: Problem beim rekursiven Prozedur-Aufruf

Beitrag 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
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Problem beim rekursiven Prozedur-Aufruf

Beitrag 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).
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Problem beim rekursiven Prozedur-Aufruf

Beitrag 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.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Antworten