Me pidieron que calcule la siguiente expresión de raíz anidada usando solo recursión .
Escribí el siguiente código que funciona, pero nos permitieron usar solo una función y 1 entrada n
para el propósito y no 2 como usé. ¿Alguien puede ayudarme a transformar este código en una función que calcule la expresión? No puedo usar ninguna biblioteca excepto las funciones de <math.h>
.
salida para 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()
(desde<stdlib.h>
), no devolvería silenciosamente 0.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; }
Respuestas:
Use los bits superiores de
n
como contador:Naturalmente, eso funciona mal cuando la inicial
n
esR
o mayor. Aquí hay una versión más complicada que funciona para cualquier valor positivo den
. Funciona:n
es negativo, funciona como la versión anterior, utilizando los bits superiores para contar.n
es positivo, si es menor queR
, se llama a sí mismo-n
para evaluar la función como se indicó anteriormente. De lo contrario, se llama a sí mismo conR-1
negado. Esto evalúa la función como si se llamara conR-1
. Esto produce el resultado correcto porque la serie deja de cambiar en el formato de punto flotante después de unas pocas docenas de iteraciones: las raíces cuadradas de los números más profundos se diluyen tanto que no tienen ningún efecto. Por lo tanto, la función tiene el mismo valor para todosn
en un umbral pequeño.fuente
R
está separado, por lo que se puede ajustar. Antes den
llegar a 32, el valor de retorno deja de cambiar para IEEE-754 binary64, y antes de llegar a 256, el valor de retorno deja de cambiar para formatos razonables paradouble
. Así que estoy considerando una versión alternativa que transforma las entradas de las abrazaderas anterioresR
, pero necesita usar el bit de signo, y todavía estoy trabajando en ello.n
independientemente del ancho deint
.Sin transformar matemáticamente la fórmula (no sé si es posible), no puede usar realmente un solo parámetro, ya que para cada elemento necesita dos informaciones: el paso actual y el original
n
. Sin embargo, puedes hacer trampa . Una forma es codificar los dos números en elint
parámetro (como lo muestra Eric ).Otra forma es almacenar el original
n
en una variable local estática. En la primera llamada que guardamosn
en esta variable estática, comenzamos la recursión y en el último paso la restablecemos al valor centinela:Aparentemente
static int n = sentinel
no es C estándar porquesentinel
no es una constante de tiempo de compilación en C (es extraño porque tanto gcc como clang no se quejan, incluso con-pedantic
)Puedes hacer esto en su lugar:
fuente
static int n = sentinel;
no es totalmente conforme en C porquesentinel
no es una expresión constante según el Estándar C. Funciona en C ++, y se compila con las versiones actuales de gcc y clang en modo C, pero no en MSVC 2017, pero probablemente debería escribirstatic int n = -1;
vea godbolt.org/z/8pEMnzEste problema pide soluciones retorcidas.
Aquí hay uno que usa una sola función tomando uno o dos
int
argumentos:<stdarg.h>
que podría o no estar permitido.Aquí está el código:
Aquí hay otra solución con una sola función, usando solo
<math.h>
, pero abusando de las reglas de una manera diferente: usando una macro.Otro más, estrictamente hablando recursivo , pero con un solo nivel de recursión y sin otros trucos. Como Eric comentó, usa un
for
bucle que podría ser inválido bajo las restricciones del OP:fuente
double rec_sqrt_series(int n)
, IMO cumple con los objetivos de OP utilizando el signo como una bandera de recursión. (else
return
if
else
descartar es posible, por supuesto, pero me gusta un poco la simetría de ambas ramas de laif
devolución de un resultado, una especie de estilo de programación funcional.Aquí hay otro enfoque.
Se basa en
int
ser de 32 bits. La idea es utilizar los 32 bits superiores de 64 bitsint
para1) Vea si la llamada fue recursiva (o una llamada desde el "exterior")
2) Guarde el valor objetivo en los 32 bits superiores durante la recursividad
fuente