Quando è diventato un codice golf? Ho pensato che fosse una sfida al codice trovare il miglior algoritmo!
code-golf
APL, 33 caratteri
{r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6}
Questa è una semplice ricerca lineare, a partire da C = 1 + 10 -6 e incrementandola di 10 -6 fino al
registro C registro C registro C ⋯ A ≤ 1
dove il registro C funzione viene applicata ricorsivamente B volte.
Esempi
4 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 65536
2.0000009999177335
3 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 7625597484987
3.0000000000575113
Questo codice è molto lento, ma per basi piccole come 2 o 3 si completa in pochi secondi. Vedi sotto per una cosa migliore.
code-challenge
APL, complessità logaritmica
Complessità realmente lineare sull'ordine delle radici, logaritmica sulla dimensione del risultato e precisione:
tempo = O (B × registro (C) + B × registro (D))
dove B è l'ordine di root, C è la base di tetrazione richiesta e D è il numero di cifre di precisione richieste. Questa complessità è la mia comprensione intuitiva, non ho prodotto una prova formale.
Questo algoritmo non richiede numeri interi grandi, utilizza solo la funzione log su numeri in virgola mobile regolari, quindi è abbastanza efficiente su numeri molto grandi, fino al limite dell'implementazione in virgola mobile (doppia precisione o numeri FP arbitrari di grandi dimensioni sul Implementazioni APL che li offrono.)
La precisione del risultato può essere controllata impostando ⎕CT(tolleranza di confronto) sull'errore accettabile desiderato (sul mio sistema il valore predefinito è 1e¯14, circa 14 cifre decimali)
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.
}
Non sono sicuro se 1≥⍵⍟⍣nsopra potrebbe fallire con un errore di dominio (perché il registro di un argomento negativo potrebbe fallire immediatamente o dare un risultato complesso, che non sarebbe nel dominio di ≥) ma non sono stato in grado di trovare un caso che fallisce.
Esempi
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' viene visualizzato come valore esatto perché risulta essere uno dei valori direttamente colpiti dalla ricerca binaria (a partire da 2, raddoppiato a 4, bisecare a 3). Nel caso generale ciò non accada, quindi il risultato approssimerà il valore della radice con un errore ⎕CT (più precisamente, il test logaritmico di ogni base candidata viene eseguito con tolleranza TCT.)