Calculer la super racine d'un nombre

10

En mathématiques, la tétration est l'hyper opérateur suivant après l'exponentiation, et est définie comme l'exponentiation itérée.

Addition ( a réussi n fois)

Multiplication ( a ajouté à lui-même, n fois)

Exponentiation ( a multipliée par elle-même, n fois)

Tétration ( un exponentielles par lui - même, n fois)

Les relations inverses de la tétration sont appelées la super-racine et le super-logarithme. Votre tâche est d'écrire un programme qui, étant donné A et B, imprime B e -order super-racine de A.

Par exemple:

  • si A = 65,536et B = 4il imprime2
  • si A = 7,625,597,484,987et B = 3il imprime3

A et B sont des entiers positifs et le résultat doit être un nombre à virgule flottante avec une précision de 5 chiffres après la virgule décimale. Le résultat appartient au domaine réel.

Attention, les super-racines peuvent avoir de nombreuses solutions.

Andrea Ciceri
la source
1
Y a-t-il des limites minimum / maximum sur les numéros d'entrée? Une réponse valide doit-elle prendre en charge les réponses à virgule flottante, ou uniquement un entier?
Josh
3
Si plusieurs solutions, le programme doit-il en trouver toutes ou une seule?
Johannes H.
5
Alors, quels sont vos critères de réussite?
Mhmd
2
Pouvez-vous donner un exemple simple d'une super-racine qui a plus d'une solution pour un A et B ≥ 1 donné?
Tobia
1
Pouvez-vous donner la représentation mathématique d'une super-racine? Je crains de ne toujours pas comprendre comment cela est défini.

Réponses:

6

C - viser la clarté, n'a pas tenté de presser le code

Considérant l'entrée:

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

Ensuite, il ne devrait généralement y avoir qu'une seule solution dans ℝ, ce qui simplifie considérablement le problème.

Le code est:

#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;
}

Compiler:

gcc -o tet_root tet_root.c -lm

Courir:

./tet_root A B

Par exemple:

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 comme n ➙ ∞? (limite bien connue)

$ ./tet_root 2 10
1.416190

$ ./tet_root 2 100
1.414214

$ ./tet_root 2 1000
1.414214

Oui!

n (e 1 / e ) ➙ ∞ comme n ➙ ∞? (limites supérieures)

$ ./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

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


la source
Vous savez en fait beaucoup de choses sur les mathématiques que je peux dire :) (Cette réponse) ∈ (Des choses vraiment impressionnantes)
Albert Renshaw
@AlbertRenshaw Ceci n'est qu'une implémentation de la bissection. Pas très dur du tout.
Simply Beautiful Art
5

Python, 87 caractères

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

Une simple recherche linéaire de la réponse.

Hors sujet, mais qu'est-ce que * # $ (@! Est en place avec l' **opérateur python ?

>>> 1e200*1e200
inf
>>> 1e200**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')
Keith Randall
la source
Digne d'un rapport de bug?
Josh
L'associativité fait-elle obstacle? Peut-être vous comparez (1e200)**2à 1e(200**2)?
danmcardle
2
@Josh: J'ai signalé un bug: bugs.python.org/issue20543 Fondamentalement, fonctionnant comme prévu - ils ne sont pas beaucoup pour IEEE float. S'ils devaient réparer quoi que ce soit, ce serait d'en générer un OverflowErrordans le premier cas.
Keith Randall
3

Mathematica, 35 40

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

Génère une liste de toutes les solutions, avec une précision à 5 chiffres.

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

5 caractères supplémentaires pour obtenir uniquement la vraie solution, comme l'exigent les règles mises à jour.

shrx
la source
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

Instruction en virgule flottante ignorée car la question définit uniquement le comportement des entiers.

gggg
la source
2

Quand est-ce devenu un golf à code? Je pensais que c'était un défi de code pour trouver le meilleur algorithme!


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.


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

Tobia
la source
1

Rubis, 79 octets

->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}

C'est le même que le programme ci-dessous, mais moins précis car il n'exécute que 99 boucles.

Rubis, 87 octets

->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}

Essayez-le en ligne

C'est simplement une bissection. Non golfé:

-> 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
}
Art tout simplement magnifique
la source
0

k [52 caractères]

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

Une version modifiée de mon propre post n ième racine

Exemple:

{{{((%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
nyi
la source
0

Haskell

Recherche linéaire simple, renvoie d'abord, la plus petite correspondance trouvée.

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

Exemple

*Main> superRoot 65536 4
2
*Main> superRoot 7625597484987 3
3
danmcardle
la source
0

Mathematica, 41 octets sans optimisation

Mathematica a été inventé pour résoudre des problèmes comme celui-ci. Une solution simple consiste à construire le problème sous la forme d'une série de puissances imbriquées et à le transmettre à la Reducefonction intégrée, qui recherche des solutions analytiques aux équations. En conséquence, ce qui suit, en plus d'être du code inhabituellement concis, n'est pas non plus une force brute.

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

Vous pouvez supprimer la restriction pour ne fournir que des solutions de nombre réel si vous êtes patient et souhaitez économiser six octets. Vous pouvez également exprimer certaines des fonctions imbriquées sous forme abrégée pour économiser quelques octets supplémentaires. Comme indiqué, il revient ainsi

entrez la description de l'image ici

Michael Stern
la source
0

05AB1E , 16 octets

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

Port de la réponse Python de @KeithRandall .

Essayez-le en ligne.

Explication:

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}pourrait également être D²>и.»mpour le même nombre d'octets:

  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
Kevin Cruijssen
la source