Calcola la super radice di un numero


10

In matematica, la tetrazione è il successivo operatore ipertestuale dopo esponenziazione ed è definita come esponenziazione iterata.

Aggiunta ( un successo n volte)

Moltiplicazione ( un aggiunto a se stesso, n volte)

Exponentiation ( a moltiplicato per se stesso, n volte)

Tetrazione ( un esponente di per sé, n volte)

Le relazioni inverse di tetrazione sono chiamate super-radice e super-logaritmo. Il vostro compito è quello di scrivere un programma che, dato A e B, stampa i B ND -order super-radice di A.

Per esempio:

  • se A = 65,536e B = 4stampa2
  • se A = 7,625,597,484,987e B = 3stampa3

A e B sono numeri interi positivi e il risultato deve essere un numero in virgola mobile con una precisione di 5 cifre dopo il punto decimale. Il risultato appartiene al dominio reale.

Fai attenzione, le super radici possono avere molte soluzioni.


1
Ci sono limiti minimi / massimi sui numeri di input? Una risposta valida dovrebbe supportare risposte in virgola mobile o solo numeri interi?
Josh,

3
Se più soluzioni, il programma dovrebbe trovare tutte o solo una?
Johannes H.

5
Quindi quali sono i tuoi criteri vincenti?
Mhmd

2
Puoi dare un semplice esempio di un super-root che ha più di una soluzione per un dato A e B ≥ 1?
Tobia,

1
Puoi dare la rappresentazione matematica di una super-radice? Temo di non capire ancora come sia definito.

Risposte:


6

C - mirando alla chiarezza, non ha tentato di spremere il codice

Considerando input:

A: A ∈ ℝ, A ≥ 1.0
B: B ∈ ℕ, B ≥ 1

Quindi di solito dovrebbe esserci solo una soluzione in ℝ, che semplifica notevolmente il problema.

Il codice è:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define TOLERANCE    1.0e-09

double tetrate(double, int);

int main(int argc, char **argv)
{
    double target, max, min, mid, working;
    int levels;

    if (argc == 3)
    {
        target = atof(argv[1]); // A
        levels = atoi(argv[2]); // B

        // Shortcut if B == 1
        if (levels == 1)
        {
            printf("%f\n", target);
            return 0;
        }

        // Get a first approximation
        max = 2.0;
        while (tetrate(max, levels) < target)
            max *= 2.0;

        min = max / 2.0;

        // printf("Answer is between %g and %g\n", min, max);

        // Use bisection to get a closer approximation
        do
        {
            mid = (min + max) / 2.0;
            working = tetrate(mid, levels);
            if (working > target)
                max = mid;
            else if (working < target)
                min = mid;
            else
                break;
        }
        while (max - min > TOLERANCE);

        // printf("%g: %f = %f tetrate %d\n", target, tetrate(mid, levels), mid, levels);
        printf("%f\n", mid);
    }

    return 0;
}

double tetrate(double d, int i)
{
    double result = d;

    // If the result is already infinite, don't tetrate any more
    while (--i && isfinite(result))
        result = pow(d, result);

    return result;
}

Compilare:

gcc -o tet_root tet_root.c -lm

Correre:

./tet_root A B

Per esempio:

4 2

$ ./tet_root 65536 4
2.000000

3 3

$ ./tet_root 7625597484987 3
3.000000

3 π

$ ./tet_root 1.340164183e18 3
3.141593

n (2 ½ ) ➙ 2 come n ➙ ∞? (limite ben noto)

$ ./tet_root 2 10
1.416190

$ ./tet_root 2 100
1.414214

$ ./tet_root 2 1000
1.414214

Sì!

n (e 1 / e ) ➙ ∞ come n ➙ ∞? (limiti superiori)

$ ./tet_root 9.999999999e199 100
1.445700

$ ./tet_root 9.999999999e199 1000
1.444678

$ ./tet_root 9.999999999e199 10000
1.444668

$ ./tet_root 9.999999999e199 100000
1.444668

Freddo! (e 1 / e ≅ 1.44466786101 ...)


In realtà sai molto della matematica che posso dire :) (Questa risposta) ∈ (roba davvero impressionante)
Albert Renshaw,

@AlbertRenshaw Questa è solo un'implementazione di bisection. Per niente difficile.
Arte semplicemente

5

Python, 87 caratteri

E=lambda x,n:x**E(x,n-1)if n else 1
def S(A,B):
 x=1.
 while E(x,B)<A:x+=1e-5
 return x

Una semplice ricerca lineare per la risposta.

Fuori tema, ma cosa sta succedendo * # $ (@! Con l' **operatore python ?

>>> 1e200*1e200
inf
>>> 1e200**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

Degno di una segnalazione di bug?
Josh,

L'associatività si sta mettendo in mezzo? Forse si sta confrontando (1e200)**2a 1e(200**2)?
danmcardle,

2
@Josh: ho segnalato un bug: bugs.python.org/issue20543 Fondamentalmente, funzionando come previsto - non sono molto per il float IEEE. Se dovessero risolvere qualcosa, sarebbe generare un OverflowErrorprimo caso.
Keith Randall

3

Mathematica, 35 40

n /. Solve[Nest[#^(1/n) &, a, b] == n]~N~5

Genera un elenco di tutte le soluzioni, con precisione a 5 cifre.

n /. Last@Solve[Nest[#^(1/n) &, a, b] == n]~N~5

Altri 5 personaggi per ottenere solo la vera soluzione, richiesta dalle regole aggiornate.


2

Julia

julia> t(a,b)=(c=a;for j=1:b-1;c=a^c;end;c)
julia> s(c,b)=(i=1;while t(i,b)!=c;i+=1;end;i)
julia> s(65536,4)
2
julia> s(7625597484987,3)     
3

Istruzione in virgola mobile ignorata poiché la domanda definisce solo il comportamento degli interi.


2

Quando è diventato un codice golf? Ho pensato che fosse una sfida al codice trovare il miglior algoritmo!


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.


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.)


1

Rubino, 79 byte

->a,b{x=y=1.0;z=a;eval"y=(x+z)/2;x,z=a<eval('y**'*~-b+?y)?[x,y]:[y,z];"*99;p y}

È lo stesso del programma seguente, ma è meno preciso poiché esegue solo 99 loop.

Rubino, 87 byte

->a,b{x=y=1.0;z=a;(y=(x+z)/2;x,z=a<eval("y**"*~-b+?y)?[x,y]:[y,z])while y!=(x+z)/2;p y}

Provalo online

Questa è semplicemente bisection. Ungolfed:

-> a, b {
    # y^^b by evaluating the string "y ** y ** ..."
    tetration =-> y {eval "y ** " * (b-1) + ?y}

    lower = middle = 1.0
    upper = a

    while middle != (lower + upper) / 2 do
        middle = (lower + upper) / 2

        if tetration[middle] > a
            upper = middle
        else
            lower = middle
        end
    end

    print middle
}

0

k [52 caratteri]

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}

Una versione modificata del mio post proprio n esima radice

Esempio:

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}[7625597484987;3]
3f 

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}[65536;4]
2f

0

Haskell

Ricerca lineare semplice, restituisce prima la corrispondenza più piccola trovata.

{-
    The value of a is the result of exponentiating b some number of times.
    This function computes that number.
-}
superRoot a b = head [x | x<-[2..a], tetrate x b == a]

{-
    compute b^b^...^b repeated n times
-}
tetrate b 1 = b
tetrate b n = b^(tetrate b (n-1))

Esempio

*Main> superRoot 65536 4
2
*Main> superRoot 7625597484987 3
3

0

Mathematica, 41 byte senza ottimizzazione

Mathematica è stata sostanzialmente inventata per risolvere problemi come questo. Una soluzione semplice è quella di costruire il problema come una serie di potenze nidificate e passarlo alla Reducefunzione integrata, che cerca soluzioni analitiche alle equazioni. Di conseguenza, oltre a essere un codice insolitamente conciso, anche il seguente non è forza bruta.

Reduce[Nest[Power[#, 1/x] &, a, b] == x, x, Reals]

È possibile rimuovere la restrizione per fornire solo soluzioni con numeri reali se si è pazienti e si desidera salvare sei byte. È inoltre possibile esprimere alcune delle funzioni nidificate in forma abbreviata per salvare qualche altro byte. Come dato, ritorna così

inserisci qui la descrizione dell'immagine


0

05AB1E , 16 byte

1[ÐU²FXm}¹@#5(°+

Porta della risposta Python di @KeithRandall .

Provalo online.

Spiegazione:

1                 # Push a 1
 [                # Start an infinite loop:
  Ð               #  Triplicate the top value on the stack
   U              #  Pop and store one in variable `X`
    ²F            #  Inner loop the second input amount of times:
      Xm          #   And take the top value to the power `X`
        }         #  After the inner loop:
         ¹@       #  If the resulting value is larger than or equal to the first input:
           #      #   Stop the infinite loop
                  #   (after which the top of the stack is output implicitly as result)
            5(°+  #  If not: increase the top value by 10^-5

ÐU²FXm}potrebbe anche essere D²>и.»mper lo stesso conteggio byte:

  D               #   Duplicate the top value on the stack
   ²>             #   Push the second input + 1
     и            #   Repeat the top value that many times as list
                #   Reduce it by:
        m         #    Taking the power
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.