Poproszono mnie o obliczenie następującego zagnieżdżonego wyrażenia głównego przy użyciu tylko rekurencji .
Napisałem poniższy kod, który działa, ale pozwolili nam użyć tylko jednej funkcji i 1 wejścia n
do tego celu, a nie 2 takich jak ja. Czy ktoś może mi pomóc przekształcić ten kod w jedną funkcję, która obliczy wyrażenie? nie mogę użyć żadnej biblioteki oprócz funkcji z <math.h>
.
wyjście dla 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()
(z<stdlib.h>
), nie po cichu zwraca 0double 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; }
Odpowiedzi:
Użyj górnych bitów
n
jako licznika:Oczywiście to działa nieprawidłowo, gdy wartość początkowa
n
jestR
większa lub większa. Oto bardziej skomplikowana wersja, która działa dla dowolnej dodatniej wartościn
. To działa:n
jest ujemne, działa jak w powyższej wersji, zliczając górne bity.n
jest dodatnia, jeśli jest mniejsza niżR
, wywołuje się w-n
celu oceny funkcji jak wyżej. W przeciwnym razie nazywa sięR-1
negacją. To ocenia funkcję tak, jakby była wywołana za pomocąR-1
. Daje to prawidłowy wynik, ponieważ seria przestaje się zmieniać w formacie zmiennoprzecinkowym po zaledwie kilkudziesięciu iteracjach - pierwiastki kwadratowe z głębszych liczb stają się tak rozcieńczone, że nie działają. Tak więc funkcja ma tę samą wartość dla całegon
małego progu.źródło
R
jest osobny, więc można go dostroić. Przedn
osiągnięciem 32 wartość zwracana przestaje się zmieniać dla IEEE-754 binary64, a zanim osiągnie 256, zwracana wartość przestaje się zmieniać dla rozsądnych formatówdouble
. Zastanawiam się więc nad alternatywną wersją, która przekształca dane zacisków powyżejR
, ale musi użyć bitu znakowego i nadal nad tym pracuję.n
niezależnie od szerokościint
.Bez matematycznego przekształcenia formuły (nie wiem, czy jest to możliwe), nie można tak naprawdę użyć tylko jednego parametru, ponieważ dla każdego elementu potrzebne są dwie informacje: bieżący krok i oryginał
n
. Możesz jednak oszukiwać . Jednym ze sposobów jest zakodowanie dwóch liczb wint
parametrze (jak pokazuje Eric ).Innym sposobem jest przechowywanie oryginału
n
w statycznej zmiennej lokalnej. Przy pierwszym wywołaniu, które zapisujemyn
w tej zmiennej statycznej, rozpoczynamy rekurencję, a na ostatnim etapie resetujemy ją do wartości wartownika:Najwyraźniej
static int n = sentinel
nie jest standardowym C, ponieważsentinel
nie jest stałą czasową kompilacji w C (to dziwne, ponieważ zarówno gcc, jak i clang nie narzekają, nawet z-pedantic
)Możesz to zrobić zamiast tego:
źródło
static int n = sentinel;
nie jest w pełni zgodny z C, ponieważsentinel
nie jest stałym wyrażeniem zgodnie ze standardem C. Działa w C ++ i kompiluje się z aktualnymi wersjami gcc i clang w trybie C, ale nie MSVC 2017, ale prawdopodobnie powinieneś napisaćstatic int n = -1;
patrz godbolt.org/z/8pEMnzTen problem wymaga wykrzywionych rozwiązań.
Oto jedna, która korzysta z jednej funkcji, biorąc jeden lub dwa
int
argumenty:<stdarg.h>
które mogą, ale nie muszą być dozwolone.Oto kod:
Oto inne rozwiązanie z pojedynczą funkcją, używając tylko
<math.h>
, ale nadużywając reguł w inny sposób: używając makra.Jeszcze jeden, ściśle rekurencyjny , ale z jednym poziomem rekurencji i bez innych sztuczek. Jak skomentował Eric , wykorzystuje
for
pętlę, która może być niepoprawna z powodu ograniczeń PO:źródło
double rec_sqrt_series(int n)
, IMO, spełnia cele OP, używając znaku jako flagi rekurencyjnej. (else
return
if
else
jest oczywiście możliwe, ale lubię symetrię obu gałęziif
zwracanego wyniku, rodzaj funkcjonalnego stylu programowania.Oto inne podejście.
Polega na
int
byciu 32 bitami. Chodzi o to, aby korzystać z górną 32 bit 64 bitint
do1) Sprawdź, czy połączenie było połączeniem rekurencyjnym (czy połączeniem „z zewnątrz”)
2) Zapisz wartość docelową w górnych 32 bitach podczas rekurencji
źródło