Calcular a super raiz de um número

10

Em matemática, a tetração é o próximo hiperoperador após a exponenciação e é definida como exponenciação iterada.

Adição ( um sucesso n vezes)

Multiplicação ( a adicionada a si mesma, n vezes)

Exponenciação ( um multiplicado por si mesmo, n vezes)

Tetração ( a exponenciada por si mesma, n vezes)

As relações inversas da tetração são chamadas de super-raiz e super-logaritmo. Sua tarefa é escrever um programa que, dado A e B, imprime o B nd -order super-raiz de A.

Por exemplo:

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

A e B são números inteiros positivos e o resultado deve ser um número de ponto flutuante com uma precisão de 5 dígitos após o ponto decimal. O resultado pertence ao domínio real.

Cuidado, as super-raízes podem ter muitas soluções.

Andrea Ciceri
fonte
11
Existem limites mínimo / máximo nos números de entrada? Uma resposta válida deve suportar respostas de ponto flutuante ou apenas um número inteiro?
21413 Josh
3
Se houver várias soluções, o programa deve encontrar todas ou apenas uma?
Johannes H.
5
Então, qual é o seu critério de vitória?
Mhmd
2
Você pode dar um exemplo simples de uma super raiz que tem mais de uma solução para um dado A e B ≥ 1?
Tobia 07/02
11
Você pode dar a representação matemática de uma super raiz? Receio ainda não entender como é definido.

Respostas:

6

C - visando clareza, não tentou espremer o código

Considerando a entrada:

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

Em geral, deve haver apenas uma solução em ℝ, o que simplifica consideravelmente o problema.

O código é:

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

Compilar:

gcc -o tet_root tet_root.c -lm

Para correr:

./tet_root A B

Por exemplo:

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 como n ∞ ∞? (limite conhecido)

$ ./tet_root 2 10
1.416190

$ ./tet_root 2 100
1.414214

$ ./tet_root 2 1000
1.414214

Sim!

n (e 1 / e ) ∞ como n ➙ ∞? (limites superiores)

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

Legal! (e 1 / e ≅ 1,44466786101 ...)


fonte
Você realmente sabe muito sobre matemática que eu posso dizer :) (Esta resposta) ∈ (coisas ℝeally impressionante)
Albert Renshaw
@AlbertRenshaw Esta é apenas uma implementação de bissecção. Não é muito difícil.
236208 Simply Simples Art
5

Python, 87 caracteres

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

Uma pesquisa linear simples para a resposta.

Fora do tópico, mas o que o * # $ (@! Está acontecendo com o **operador 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
fonte
Digno de um relatório de bug?
217 Josh Josh
A associatividade está atrapalhando? Talvez você esteja comparando (1e200)**2com 1e(200**2)?
Danmcardle
2
@ Josh: Eu relatei um bug: bugs.python.org/issue20543 Basicamente, funcionando como pretendido - eles não são muito para o IEEE float. Se eles deveriam consertar alguma coisa, seria gerar um OverflowErrorno primeiro caso.
Keith Randall
3

Mathematica, 35 40

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

Gera uma lista de todas as soluções, com precisão de 5 dígitos.

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

Mais 5 caracteres para obter apenas a solução real, exigida pelas regras atualizadas.

shrx
fonte
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

Instrução de ponto flutuante ignorada, pois a pergunta define apenas o comportamento para números inteiros.

gggg
fonte
2

Quando isso se tornou um código de golfe? Eu pensei que era um desafio de código apresentar o melhor algoritmo!


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.


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

Tobia
fonte
1

Ruby, 79 bytes

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

É o mesmo que o programa abaixo, mas menos preciso, pois executa apenas 99 loops.

Ruby, 87 bytes

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

Experimente online

Isto é simplesmente bissecção. 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
}
Arte simplesmente bonita
fonte
0

k [52 caracteres]

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

Uma versão modificada do meu post n º raiz

Exemplo:

{{{((%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
fonte
0

Haskell

Pesquisa linear simples, retorna primeiro, menor correspondência encontrada.

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

Exemplo

*Main> superRoot 65536 4
2
*Main> superRoot 7625597484987 3
3
danmcardle
fonte
0

Mathematica, 41 bytes sem otimização

O Mathematica foi basicamente inventado para resolver problemas como esse. Uma solução fácil é construir o problema como uma série de potências aninhada e passá-lo para a Reducefunção interna, que busca soluções analíticas para equações. Como resultado, o seguinte, além de ser um código incomumente conciso, também não é uma força bruta.

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

Você pode remover a restrição para fornecer apenas soluções de números reais se tiver paciência e desejar salvar seis bytes. Você também pode expressar algumas das funções aninhadas de forma abreviada para salvar mais alguns bytes. Como dado, retorna assim

insira a descrição da imagem aqui

Michael Stern
fonte
0

05AB1E , 16 bytes

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

Porto da resposta em Python do @KeithRandall .

Experimente online.

Explicação:

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}também pode ser D²>и.»mpara a mesma contagem de bytes:

  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
fonte