Quando isso se tornou um código de golfe? Eu pensei que era um desafio de código apresentar o melhor algoritmo!
código-golfe
APL, 33 caracteres
{r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6}
Esta é uma pesquisa linear simples, iniciando em C = 1 + 10 -6 e incrementando-a em 10 -6 até o
log C log C log C C A ≤ 1
onde a função log C é aplicada recursivamente B vezes.
Exemplos
4 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 65536
2.0000009999177335
3 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 7625597484987
3.0000000000575113
Esse código é muito lento, mas para pequenas bases, como 2 ou 3, é concluído em alguns segundos. Veja abaixo uma coisa melhor.
desafio de código
APL, complexidade logarítmica
Na verdade, complexidade linear na ordem das raízes, logarítmica no tamanho e precisão do resultado:
tempo = O (B × log (C) + B × log (D))
onde B é a ordem raiz, C é a base de tetragem solicitada e D é o número de dígitos de precisão solicitados. Essa complexidade é meu entendimento intuitivo, não produzi uma prova formal.
Esse algoritmo não requer números inteiros grandes, ele usa apenas a função log em números regulares de ponto flutuante; portanto, é bastante eficiente em números muito grandes, até o limite da implementação do ponto flutuante (precisão dupla ou números FP grandes e arbitrários no Implementações de APL que as oferecem.)
A precisão do resultado pode ser controlada configurando ⎕CT(tolerância de comparação) para o erro aceitável desejado (no meu sistema, o padrão é 1e¯14, aproximadamente 14 dígitos decimais)
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.
}
Não tenho certeza se 1≥⍵⍟⍣nacima pode falhar com um erro de domínio (porque o log de um argumento negativo pode falhar imediatamente ou fornecer um resultado complexo, que não estaria no domínio de ≥), mas não consegui encontrar um caso que falha.
Exemplos
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' sai como um valor exato, porque é um dos valores atingidos diretamente pela pesquisa binária (começando de 2, dobrado para 4, bissetrado para 3). No caso geral de isso não acontecer, o resultado aproximará o valor raiz com um erro de ⎕CT (mais precisamente, o teste logarítmico de cada base candidata é realizado com tolerância ⎕CT).