Hacer el auto-super-logaritmo


18

Dado un número entero positivo n y un número a , el n -ésimo tetración de una se define como un ^ ( un ^ ( un ^ (... ^ una ))), donde ^ denota exponenciación (o potencia) y la expresión contiene el número de una exactamente n veces.

En otras palabras, la tetración es exponenciación iterativa asociativa derecha. Para n = 4 y a = 1.6 la tetración es 1.6 ^ (1.6 ^ (1.6 ^ 1.6)) ≈ 3.5743.

La función inversa de la tetración con respecto a n es el superlogaritmo . En el ejemplo anterior, 4 es el superlogaritmo de 3.5743 con "superbase" 1.6.

El reto

Dado un número entero positivo n , encuentre x tal que n sea ​​el superlogaritmo de sí mismo en la superbase x . Es decir, encuentre x tal que x ^ ( x ^ ( x ^ (... ^ x ))) (con x apareciendo n veces) es igual a n .

Reglas

Programa o función permitida.

Los formatos de entrada y salida son flexibles como de costumbre.

El algoritmo debería funcionar teóricamente para todos los enteros positivos. En la práctica, la entrada puede limitarse a un valor máximo debido a restricciones de memoria, tiempo o tipo de datos. Sin embargo, el código debe funcionar para entradas hasta al 100menos en menos de un minuto.

El algoritmo teóricamente debería dar el resultado con 0.001precisión. En la práctica, la precisión de salida puede ser peor debido a los errores acumulados en los cálculos numéricos. Sin embargo, la salida debe ser precisa 0.001para los casos de prueba indicados.

El código más corto gana.

Casos de prueba

1    ->  1
3    ->  1.635078
6    ->  1.568644
10   ->  1.508498
25   ->  1.458582
50   ->  1.448504
100  ->  1.445673

Implementación de referencia

Aquí hay una implementación de referencia en Matlab / Octave (pruébelo en Ideone ).

N = 10; % input
t = .0001:.0001:2; % range of possible values: [.0001 .0002 ... 2]
r = t;
for k = 2:N
    r = t.^r; % repeated exponentiation, element-wise
end
[~, ind] = min(abs(r-N)); % index of entry of r that is closest to N
result = t(ind);
disp(result)

Por N = 10esto da result = 1.5085.

El siguiente código es una verificación de la precisión de salida, usando aritmética de precisión variable:

N = 10;
x = 1.5085; % result to be tested for that N. Add or subtract 1e-3 to see that
            % the obtained y is farther from N
s = num2str(x); % string representation
se = s;
for n = 2:N;
    se = [s '^(' se ')']; % build string that evaluates to iterated exponentiation
end
y = vpa(se, 1000) % evaluate with variable-precision arithmetic

Esto da:

  • Para x = 1.5085:y = 10.00173...
  • Para x = 1.5085 + .001:y = 10.9075
  • Por x = 1.5085 - .001eso da y = 9.23248.

Por lo tanto, 1.5085es una solución válida con .001precisión.


Relacionados . Las diferencias son que la (super) base del superlogaritmo aquí no es fija, y el resultado no es un número entero en general.
Luis Mendo

Parece que la función converge bastante rápido. Si nuestro algoritmo es simplemente un ajuste de curva que está dentro de 0.001, ¿eso cuenta como un trabajo teórico para todos los enteros positivos?
xnor


@KevinCruijssen Tengo una implementación de referencia en Matlab basada en la búsqueda binaria que es razonablemente rápida. Puedo publicarlo si eso es útil
Luis Mendo

1
¿ xConverge a medida que se nacerca al infinito?
mbomb007

Respuestas:


3

Dyalog APL , 33 25 bytes

Necesidades, lo ⎕IO←0cual es predeterminado en muchos sistemas.

⌈/⎕(⊢×⊣≥(*/⍴)¨)(1+⍳÷⊢)1E4

Calcula teóricamente para todos los enteros, pero prácticamente limitado a uno muy pequeño.

TryAPL en línea!


¿Funciona lo suficientemente rápido en la entrada 100?
Greg Martin

@ GregMartin No hay suficiente memoria.
Adám

10

Haskell, 55 54 52 bytes

s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!floor n]!!0

Uso:

> s 100
1.445600000000061

¡Gracias a @nimi por 1 byte!
Gracias a @xnor por 2!


1
[ ]!!0en lugar de head[ ]guardar un byte
nimi

1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0sería más corto si pudiera hacer que Haskell aceptara sus tipos.
xnor

@xnor Jugué con iterate cuando lo escribí en realidad, pero de alguna manera resultó más largo en ese momento
BlackCap

6

Javascript, ES6: 77 bytes / ES7: 57 53 bytes

ES6

n=>eval("for(x=n,s='x';--x;s=`Math.pow(x,${s})`);for(x=2;eval(s)>n;)x-=.001")

ES7

Utilizando **según lo sugerido por DanTheMan:

n=>eval("for(x=2;eval('x**'.repeat(n)+1)>n;)x-=.001")

Ejemplo

let f =
n=>eval("for(x=n,s='x';--x;s=`Math.pow(x,${s})`);for(x=2;eval(s)>n;)x-=.001")

console.log(f(25));


Si usa ES7, puede usar en **lugar de Math.pow.
DanTheMan

4

Mathematica, 40 33 bytes

¡Gracias a murphy por un ahorro de casi el 20%!

1//.x_:>x+.001/;Nest[x^#&,1,#]<#&

Nest[x^#&,1,n]produce la enésima tetración de x. Por lo tanto, Nest[x^#&,1,#]<#prueba si la (entrada) th tentación de x es menor que (entrada). Simplemente comenzamos en x = 1 y agregamos 0.001 repetidamente hasta que la tentación es demasiado grande, luego emitimos el último valor de x (por lo que se garantiza que la respuesta será mayor que el valor exacto, pero dentro de 0.001).

Como estoy aprendiendo lentamente: //.x_:>y/;zo //.x_/;z:>ysignifica "buscar cualquier cosa que coincida con la plantilla x, pero solo las cosas para las cuales la prueba z devuelve verdadero; y luego operar en x por la regla y; repetidamente hasta que nada cambie". Aquí la plantilla x_es simplemente "cualquier número que veo", aunque en otros contextos podría estar más restringido.

Cuando la entrada es al menos 45, la tetración aumenta tan rápidamente que el último paso provoca un error de desbordamiento; pero el valor de x todavía se actualiza y se muestra correctamente. Disminuir el tamaño del paso de 0.001 a 0.0001 soluciona este problema para entradas de hasta 112, y brinda una respuesta más precisa al inicio (y aún se ejecuta rápidamente, en aproximadamente un cuarto de segundo). Pero ese es un byte extra, ¡así que olvídalo!

Versión original:

x=1;(While[Nest[x^#&,1,#]<#,x+=.001];x)&

Golfed un poco:1//.x_:>x+.001/;Nest[x^#&,1,#]<#&
murphy

@murphy: ¡genial! Juro que aún llegaré al punto en que pueda usarlo //.sin ayuda :)
Greg Martin

4

J, 39 31 28 bytes

(>./@(]*[>^/@#"0)1+i.%])&1e4

Basado en la implementación de referencia. Solo tiene una precisión de tres decimales.

Se guardaron 8 bytes usando el método de la solución de @ Adám .

Uso

Comandos adicionales utilizados para formatear múltiples entradas / salidas.

   f =: (>./@(]*[>^/@#"0)1+i.%])&1e4
   (,.f"0) 1 3 6 10 25 50 100
  1      0
  3  1.635
  6 1.5686
 10 1.5084
 25 1.4585
 50 1.4485
100 1.4456
   f 1000
1.4446

Explicación

(>./@(]*[>^/@#"0)1+i.%])&1e4  Input: n
                         1e4  The constant 10000
(                      )      Operate on n (LHS) and 10000 (RHS)
                   i.           The range [0, 10000)
                      ]         Get (RHS) 10000
                     %          Divide each in the range by 10000
                 1+             Add 1 to each
     (          )               Operate on n (LHS) and the range (RHS)
             #"0                  For each in the range, create a list of n copies
          ^/@                     Reduce each list of copies using exponentation
                                  J parses from right-to-left which makes this
                                  equivalent to the tetration
        [                         Get n
         >                        Test if each value is less than n
      ]                           Get the initial range
       *                          Multiply elementwise
 >./@                           Reduce using max and return

4

Python, 184 bytes

def s(n):
 def j(b,i):
  if i<0.1**12:
   return b
  m = b+i
  try:
   v = reduce(lambda a,b:b**a,[m]*n)
  except:
   v = n+1
  return j(m,i/2) if v<n else j(b,i/2)
 return j(1.0,0.5)

Salida de prueba (omitiendo las declaraciones de impresión reales):

   s(1) 1.0
   s(3) 1.63507847464
   s(6) 1.5686440646
  s(10) 1.50849792026
  s(25) 1.45858186605
  s(50) 1.44850389566
 s(100) 1.44567285047


Calcula s(1000000)bastante rápido
mbomb007

3

Raqueta 187 bytes

(define(f x n)(define o 1)(for((i n))(set! o(expt x o)))o)
(define(ur y(l 0.1)(u 10))(define t(/(+ l u)2))(define o(f t y))
(cond[(<(abs(- o y)) 0.1)t][(> o y)(ur y l t)][else(ur y t u)]))

Pruebas:

(ur 1)
(ur 3)
(ur 6)
(ur 10)
(ur 25)
(ur 50)
(ur 100)

Salida:

1.028125
1.6275390625
1.5695312499999998
1.5085021972656247
1.4585809230804445
1.4485038772225378
1.4456728475168346

Versión detallada:

(define (f x n)
  (define out 1)
  (for((i n))
    (set! out(expt x out)))
  out)

(define (uniroot y (lower 0.1) (upper 10))
  (define trying (/ (+ lower upper) 2))
  (define out (f trying y))
  (cond
    [(<(abs(- out y)) 0.1)
     trying]
    [(> out y)
     (uniroot y lower trying)]
    [else
      (uniroot y trying upper)]))

2

Perl 6 , 42 bytes

{(0,.00012).min:{abs $_-[**] $^r xx$_}}

(Traducción de ejemplo de código Matlab)

Prueba:

#! /usr/bin/env perl6
use v6.c;
use Test;

my &code = {(0,.00012).min:{abs $_-[**] $^r xx$_}}

my @tests = (
  1   => 1,
  3   => 1.635078,
  6   => 1.568644,
  10  => 1.508498,
  25  => 1.458582,
  50  => 1.448504,
  100 => 1.445673,
);

plan +@tests + 1;

my $start-time = now;

for @tests -> $_ ( :key($input), :value($expected) ) {
  my $result = code $input;
  is-approx $result, $expected, "$result ≅ $expected", :abs-tol(0.001)
}

my $finish-time = now;
my $total-time = $finish-time - $start-time;
cmp-ok $total-time, &[<], 60, "$total-time.fmt('%.3f') is less than a minute";
1..8
ok 1 - 1  1
ok 2 - 1.6351  1.635078
ok 3 - 1.5686  1.568644
ok 4 - 1.5085  1.508498
ok 5 - 1.4586  1.458582
ok 6 - 1.4485  1.448504
ok 7 - 1.4456  1.445673
ok 8 - 53.302 seconds is less than a minute

1

PHP, 103 bytes

$z=2;while($z-$a>9**-9){for($r=$s=($a+$z)/2,$i=0;++$i<$n=$argv[1];)$r=$s**$r;$r<$n?$a=$s:$z=$s;}echo$s;

1

Axioma 587 bytes

l(a,b)==(local i;i:=1;r:=a;repeat(if i>=b then break;r:=a^r;i:=i+1);r);g(q,n)==(local r,y,y1,y2,t,v,e,d,i;n<=0 or n>1000 or q>1000 or q<0 => 0;e:=1/(10**(digits()-3));v:=0.01; d:=0.01;repeat(if l(v,n)>=q then break;v:=v+d;if v>=1 and n>25 then d:=0.001;if v>=1.4 and n>40 then d:=0.0001;if v>=1.44 and n>80 then d:=0.00001;if v>=1.445 and n>85 then d:=0.000001);if l(v-d,n)>q then y1:=0.0 else y1:=v-d;y2:=v;y:=l(v,n);i:=1;if abs(y-q)>e then repeat(t:=(y2-y1)/2.0;v:=y1+t;y:=l(v,n);i:=i+1;if i>100 then break;if t<=e then break;if y<q then y1:=v else y2:=v);if i>100 then output "#i#";v)

menos golf + números

l(a,b)==
  local i
  i:=1;r:=a;repeat(if i>=b then break;r:=a^r;i:=i+1)
  r
g(q,n)==
 local r, y, y1,y2,t,v,e,d, i
 n<=0 or n>1000 or q>1000 or q<0 => 0  
 e:=1/(10**(digits()-3))
 v:=0.01; d:=0.01  
 repeat  --cerco dove vi e' il punto di cambiamento di segno di l(v,n)-q
    if l(v,n)>=q then break
    v:=v+d 
    if v>=1     and n>25 then d:=0.001
    if v>=1.4   and n>40 then d:=0.0001
    if v>=1.44  and n>80 then d:=0.00001
    if v>=1.445 and n>85 then d:=0.000001
 if l(v-d,n)>q then y1:=0.0
 else               y1:=v-d 
 y2:=v; y:=l(v,n); i:=1  -- applico il metodo della ricerca binaria
 if abs(y-q)>e then      -- con la variabile i di sicurezza
    repeat 
       t:=(y2-y1)/2.0; v:=y1+t; y:=l(v,n)
       i:=i+1
       if i>100 then break
       if t<=e  then break 
       if  y<q  then y1:=v
       else          y2:=v
 if i>100 then output "#i#"
 v

(3) -> [g(1,1), g(3,3), g(6,6), g(10,10), g(25,25), g(50,50), g(100,100)]
   Compiling function l with type (Float,PositiveInteger) -> Float
   Compiling function g with type (PositiveInteger,PositiveInteger) ->
      Float

   (3)
   [1.0000000000 000000001, 1.6350784746 363752387, 1.5686440646 047324687,
    1.5084979202 595960768, 1.4585818660 492876919, 1.4485038956 661040907,
    1.4456728504 738144738]
                                                             Type: List Float

1

Lisp común, 207 bytes

(defun superlog(n)(let((a 1d0)(i 0.5))(loop until(< i 1d-12)do(let((v(or(ignore-errors(reduce #'expt(loop for q below n collect(+ a i)):from-end t))(1+ n))))(when(< v n)(setq a (+ a i)))(setq i(/ i 2)))) a))

Usar reducecon :from-end tevita la necesidad de hacer una lambda intermedia de "exponenciación inversa" (básicamente (lambda (x y) (expt y x)), ahorrando 14 bytes (12, si elimina espacios extraíbles).

Todavía tenemos que manejar el desbordamiento de flotación, pero un ignore-errorsformulario regresa nilsi ocurrió un error, por lo que podemos usar orpara proporcionar un valor predeterminado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.