¿Cuándo se convirtió esto en un código de golf? ¡Pensé que era un desafío de código encontrar el mejor algoritmo!
código-golf
APL, 33 caracteres
{r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6}
Esta es una búsqueda lineal simple, comenzando desde C = 1 + 10 -6 e incrementándola en 10 -6 hasta
log C log C log C ⋯ A ≤ 1
donde la función log C se aplica recursivamente B veces.
Ejemplos
4 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 65536
2.0000009999177335
3 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 7625597484987
3.0000000000575113
Este código es muy lento, pero para bases pequeñas como 2 o 3 se completa en unos segundos. Vea a continuación para algo mejor.
desafío de código
APL, complejidad logarítmica
Complejidad realmente lineal en el orden raíz, logarítmica en el tamaño del resultado y precisión:
tiempo = O (B × log (C) + B × log (D))
donde B es el orden de la raíz, C es la base de la tetración que se solicita y D es el número de dígitos de precisión solicitados. Esta complejidad es mi comprensión intuitiva, no he presentado una prueba formal.
Este algoritmo no requiere números enteros grandes, solo usa la función de registro en números regulares de punto flotante, por lo tanto, es bastante eficiente en números muy grandes, hasta el límite de la implementación de punto flotante (ya sea doble precisión o números FP grandes arbitrarios en el Implementaciones de APL que las ofrecen.)
La precisión del resultado se puede controlar configurando ⎕CT
(tolerancia de comparación) el error aceptable deseado (en mi sistema, el valor predeterminado es 1e¯14, aproximadamente 14 dígitos decimales)
sroot←{ ⍝ Compute the ⍺-th order super-root of ⍵:
n←⍺ ⋄ r←⍵ ⍝ n is the order, r is the result of the tetration.
u←{ ⍝ Compute u, the upper bound, a base ≥ the expected result:
1≥⍵⍟⍣n⊢r:⍵ ⍝ apply ⍵⍟ (log base ⍵) n times; if ≤1 then upper bound found
∇2×⍵ ⍝ otherwise double the base and recurse
}2 ⍝ start the search with ⍵=2 as a first guess.
(u÷2){ ⍝ Perform a binary search (bisection) to refine the base:
b←(⍺+⍵)÷2 ⍝ b is the middle point between ⍺ and ⍵
t←b⍟⍣n⊢r ⍝ t is the result of applying b⍟ n times, starting with r;
t=1:b ⍝ if t=1 (under ⎕CT), then b is the super-root wanted;
t<1:⍺∇b ⍝ if t<1, recurse between ⍺ and b
b∇⍵ ⍝ otherwise (t>1) returse between b and ⍵
}u ⍝ begin the search between u as found earlier and its half.
}
No estoy seguro de si lo 1≥⍵⍟⍣n
anterior podría fallar con un Error de dominio (porque el registro de un argumento negativo podría fallar de inmediato o dar un resultado complejo, que no estaría en el dominio de ≥
), pero no he podido encontrar Un caso que falla.
Ejemplos
4 sroot 65536
1.9999999999999964
4 sroot 65537
2.000000185530773
3 sroot 7625597484987
3
3 sroot 7625597400000
2.999999999843567
3 sroot 7625597500000
3.000000000027626
'3' sale como un valor exacto porque resulta ser uno de los valores directamente alcanzados por la búsqueda binaria (comenzando desde 2, doblado a 4, bisecado a 3). En el caso general de que eso no suceda, el resultado se aproximará al valor raíz con un error ⎕CT (más precisamente, la prueba logarítmica de cada base candidata se realiza con tolerancia ⎕CT).