Quand est-ce devenu un golf à code? Je pensais que c'était un défi de code pour trouver le meilleur algorithme!
code-golf
APL, 33 caractères
{r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6}
Il s'agit d'une simple recherche linéaire, partant de C = 1 + 10 -6 et l'incrémentant de 10 -6 jusqu'à
log C log C log C ⋯ A ≤ 1
où la fonction log C est appliquée récursivement B fois.
Exemples
4 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 65536
2.0000009999177335
3 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 7625597484987
3.0000000000575113
Ce code est très lent, mais pour les petites bases comme 2 ou 3, il se termine en quelques secondes. Voir ci-dessous pour une meilleure chose.
code-challenge
APL, complexité logarithmique
Complexité réellement linéaire sur l'ordre racine, logarithmique sur la taille et la précision du résultat:
temps = O (B × log (C) + B × log (D))
où B est l'ordre des racines, C est la base de tétration demandée et D est le nombre de chiffres de précision demandés. Cette complexité est ma compréhension intuitive, je n'ai pas produit de preuve formelle.
Cet algorithme ne nécessite pas de grands entiers, il n'utilise la fonction log que sur les nombres à virgule flottante réguliers, il est donc assez efficace sur les très grands nombres, jusqu'à la limite de l'implémentation à virgule flottante (soit en double précision, soit en arbitraire de grands nombres FP sur le Implémentations APL qui les proposent.)
La précision du résultat peut être contrôlée en définissant ⎕CT(tolérance de comparaison) sur l'erreur acceptable souhaitée (sur mon système, elle vaut par défaut 1e¯14, soit environ 14 chiffres décimaux)
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.
}
Je ne suis pas sûr que ce qui 1≥⍵⍟⍣nprécède puisse échouer avec une erreur de domaine (car le journal d'un argument négatif pourrait soit échouer immédiatement, soit donner un résultat complexe, qui ne serait pas dans le domaine de ≥) mais je n'ai pas pu trouver un cas qui échoue.
Exemples
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' apparaît comme une valeur exacte car il se trouve que c'est l'une des valeurs directement frappées par la recherche binaire (à partir de 2, doublée à 4, bissectée à 3). Dans le cas général qui ne se produit pas, le résultat se rapproche donc de la valeur racine avec une erreur ⎕CT (plus précisément, le test logarithmique de chaque base candidate est effectué avec une tolérance ⎕CT.)