Ich wurde gebeten, den folgenden verschachtelten Root-Ausdruck nur mit Rekursion zu berechnen .
Ich habe den folgenden Code geschrieben, der funktioniert, aber sie erlaubten uns, nur eine Funktion und einen Eingang n
für diesen Zweck zu verwenden und nicht zwei, wie ich sie verwendet habe. Kann mir jemand helfen, diesen Code in eine Funktion umzuwandeln, die den Ausdruck berechnet? Ich kann keine Bibliothek außer Funktionen von verwenden <math.h>
.
Ausgabe für n = 10: 1.757932
double rec_sqrt_series(int n, int m) {
if (n <= 0)
return 0;
if (m > n)
return 0;
return sqrt(m + rec_sqrt_series(n, m + 1));
}
double helper(int n) {
return rec_sqrt_series(n, 1);
}
helper
?abort()
(von<stdlib.h>
) anrufen und nicht still 0 zurückgeben.double nested_root(unsigned n) { double x = 0.0; if (n > 0) { x = nested_root(0); for (unsigned i = n; i > 0; i--) { x = sqrt(i + x); } } return x; }
Antworten:
Verwenden Sie die oberen Bits von
n
als Zähler:Natürlich , dass Störungen , wenn die Anfangs
n
istR
oder größer ist . Hier ist eine kompliziertere Version, die für jeden positiven Wert von funktioniertn
. Es klappt:n
es negativ ist, funktioniert es wie in der obigen Version, wobei die oberen Bits zum Zählen verwendet werden.n
positiv ist, wenn es kleiner als istR
, ruft es sich selbst-n
auf, um die Funktion wie oben zu bewerten. Ansonsten ruft es sich mitR-1
negiert auf. Dies wertet die Funktion so aus, als ob sie mit aufgerufen worden wäreR-1
. Dies führt zu dem richtigen Ergebnis, da sich die Reihe nach nur wenigen Dutzend Iterationen nicht mehr im Gleitkommaformat ändert - die Quadratwurzeln der tieferen Zahlen werden so verdünnt, dass sie keine Wirkung haben. Die Funktion hat alson
über einen kleinen Schwellenwert hinweg den gleichen Wert .quelle
R
ist es separat, damit es abgestimmt werden kann. Bevorn
32 erreicht wird, ändert sich der Rückgabewert für IEEE-754 binary64 nicht mehr, und bevor er 256 erreicht, ändert sich der Rückgabewert für vernünftige Formate für nicht mehrdouble
. Ich denke also über eine alternative Version nach, die die oben genannten Klemmeingänge transformiertR
, aber das Vorzeichenbit verwenden muss, und ich arbeite noch daran.n
unabhängig von der Breite vonint
.Ohne die Formel mathematisch zu transformieren (ich weiß nicht, ob es möglich ist), können Sie nicht wirklich nur einen Parameter verwenden, da Sie für jedes Element zwei Informationen benötigen: den aktuellen Schritt und das Original
n
. Sie können jedoch betrügen . Eine Möglichkeit besteht darin, die beiden Zahlen imint
Parameter zu codieren (wie von Eric gezeigt ).Eine andere Möglichkeit besteht darin, das Original
n
in einer statischen lokalen Variablen zu speichern . Beim ersten Aufruf, den wirn
in dieser statischen Variablen speichern , starten wir die Rekursion und setzen sie im letzten Schritt auf den Sentinel-Wert zurück:Anscheinend
static int n = sentinel
ist nicht Standard C, weilsentinel
es keine Kompilierungszeitkonstante in C ist (es ist seltsam, weil sowohl gcc als auch clang sich nicht beschweren, auch nicht mit-pedantic
)Sie können dies stattdessen tun:
quelle
static int n = sentinel;
ist in C nicht vollständig konform, da ersentinel
kein konstanter Ausdruck gemäß C-Standard ist. Es funktioniert in C ++ und kompiliert mit aktuellen Versionen von gcc und clang im C-Modus, jedoch nicht mit MSVC 2017, aber Sie sollten wahrscheinlich schreiben,static int n = -1;
siehe godbolt.org/z/8pEMnzDieses Problem erfordert verzerrte Lösungen.
Hier ist eine, die eine einzelne Funktion verwendet, die ein oder zwei
int
Argumente akzeptiert:<stdarg.h>
was möglicherweise erlaubt ist oder nicht.Hier ist der Code:
Hier ist eine andere Lösung mit einer einzigen Funktion, die nur
<math.h>
die Regeln verwendet , aber auf andere Weise missbraucht: mithilfe eines Makros.Noch eine, streng genommen rekursiv , aber mit einer einzigen Rekursionsstufe und ohne andere Tricks. Wie Eric kommentierte, wird eine
for
Schleife verwendet, die unter den Einschränkungen des OP ungültig sein kann:quelle
double rec_sqrt_series(int n)
erfüllt IMO die Ziele von OP, indem das Zeichen als Rekursionsflag verwendet wird. (Ich würde das fallen lassen,else
da es nicht benötigtreturn
wirdif
.)else
ist natürlich möglich, aber ich mag es irgendwie, beide Zweige derif
Rückgabe eines Ergebnisses zu symmetrieren , eine Art funktionalen Programmierstil.Hier ist ein anderer Ansatz.
Es basiert auf
int
32 Bit. Die Idee ist, die oberen 32 Bit eines 64 Bitint
zu verwenden1) Überprüfen Sie, ob der Anruf ein rekursiver Anruf war (oder ein Anruf von "außen").
2) Speichern Sie den Zielwert während der Rekursion in den oberen 32 Bits
quelle