Esegui il super-logaritmo automatico


18

Dato un intero positivo n ed un numero a , il n -esimo tetrazione di un è definito come un ^ ( un ^ ( un ^ (^ ... un ))), dove ^ indica l'elevamento a potenza (o corrente) e l'espressione contiene il numero uno esattamente n volte.

In altre parole, la tetrazione è esponenziazione iterata associativa di destra. Per n = 4 e a = 1.6 la tetrazione è 1.6 ^ (1.6 ^ (1.6 ^ 1.6)) ≈ 3.5743.

La funzione inversa della tetrazione rispetto ad n è il super-logaritmo . Nell'esempio precedente, 4 è il super-logaritmo di 3.5743 con "super-base" 1.6.

La sfida

Dato un numero intero positivo n , trova x tale che n è il super-logaritmo di se stesso in super-base x . Cioè, trova x tale che x ^ ( x ^ ( x ^ (... ^ x ))) (con x che appare n volte) è uguale a n .

Regole

Programma o funzione consentiti.

I formati di input e output sono flessibili come al solito.

L'algoritmo dovrebbe teoricamente funzionare per tutti i numeri interi positivi. In pratica, l'input può essere limitato a un valore massimo a causa delle limitazioni di memoria, tempo o tipo di dati. Tuttavia, il codice deve funzionare per input fino ad 100almeno in meno di un minuto.

L'algoritmo dovrebbe teoricamente dare il risultato con 0.001precisione. In pratica, la precisione dell'output potrebbe essere peggiore a causa di errori accumulati nei calcoli numerici. Tuttavia, l'output deve essere accurato fino ai 0.001casi di test indicati.

Il codice più corto vince.

Casi test

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

Implementazione di riferimento

Ecco un'implementazione di riferimento in Matlab / Octave (provalo su 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)

Per N = 10questo dà result = 1.5085.

Il codice seguente è un controllo della precisione dell'output, usando l'aritmetica a precisione variabile:

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

Questo da:

  • Per x = 1.5085:y = 10.00173...
  • Per x = 1.5085 + .001:y = 10.9075
  • Perché x = 1.5085 - .001y = 9.23248.

quindi 1.5085è una soluzione valida con .001precisione.


Correlato . Le differenze sono che la (super) base del super-logaritmo qui non è fissa e il risultato non è un numero intero in generale.
Luis Mendo,

Sembra che la funzione converga piuttosto rapidamente. Se il nostro algoritmo è semplicemente una curva adatta entro 0,001, conta come funzionante teoricamente per tutti i numeri interi positivi?
xnor


@KevinCruijssen Ho un'implementazione di riferimento in Matlab basata sulla ricerca binaria che è ragionevolmente veloce. Posso pubblicarlo se è utile
Luis Mendo,

1
Non xconverge come ntende all'infinito?
mbomb007,

Risposte:


3

Dyalog APL , 33 25 byte

Necessità ⎕IO←0che è predefinita su molti sistemi.

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

Teoricamente calcola per tutti i numeri interi, ma praticamente limitato solo a uno molto piccolo.

ProvaAPL online!


Funziona abbastanza velocemente sull'ingresso 100?
Greg Martin,

@GregMartin Memoria insufficiente.
Adám,

10

Haskell, 55 54 52 byte

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

Uso:

> s 100
1.445600000000061

Grazie a @nimi per 1 byte!
Grazie a @xnor per 2!


1
[ ]!!0invece di head[ ]salvare un byte
nimi

1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0sarebbe più breve se si potesse convincere Haskell ad accettarne i tipi.
xnor

@xnor Ho giocato con iterate quando l'ho scritto in realtà, ma in qualche modo si è rivelato più lungo in quel momento
BlackCap

6

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

ES6

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

ES7

Usando **come suggerito da DanTheMan:

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

Esempio

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


Se si utilizza ES7, è possibile utilizzare **invece di Math.pow.
DanTheMan,

4

Mathematica, 40 33 byte

Grazie a Murphy per un risparmio di quasi il 20%!

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

Nest[x^#&,1,n]produce l'ennesima tetrazione di x. Quindi Nest[x^#&,1,#]<#verifica se la (input) th tetration di x è minore di (input). Iniziamo semplicemente da x = 1 e aggiungiamo ripetutamente 0,001 fino a quando la tetrazione è troppo grande, quindi emettiamo l'ultimo valore x (quindi la risposta è garantita maggiore del valore esatto, ma entro 0,001).

Come sto lentamente imparando: //.x_:>y/;zo //.x_/;z:>ysignifica "cercare qualcosa che corrisponda al modello x, ma solo le cose per le quali il test z ritorna vero; e quindi operare su x secondo la regola y; ripetutamente fino a quando non cambia nulla". Qui il modello x_è semplicemente "qualsiasi numero che vedo", sebbene in altri contesti potrebbe essere ulteriormente limitato.

Quando l'ingresso è almeno 45, la tetrazione aumenta così rapidamente che l'ultimo passaggio provoca un errore di overflow; ma il valore di x è ancora aggiornato e prodotto correttamente. La riduzione della dimensione del passaggio da 0,001 a 0,0001 risolve questo problema per input fino a 112 e fornisce una risposta più precisa all'avvio (e funziona ancora rapidamente, in circa un quarto di secondo). Ma questo è un byte in più, quindi dimenticalo!

Versione originale:

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

Ha giocato a golf un po ':1//.x_:>x+.001/;Nest[x^#&,1,#]<#&
murphy

@murphy: fantastico! Giuro che arriverò al punto in cui posso usare //.senza aiuto :)
Greg Martin,

4

J, 39 31 28 byte

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

Basato sull'implementazione di riferimento. È preciso solo con tre cifre decimali.

8 byte salvati usando il metodo dalla soluzione di @Adám .

uso

Comandi extra usati per formattare più input / output.

   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

Spiegazione

(>./@(]*[>^/@#"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 byte

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)

Test dell'output (ignorando le dichiarazioni di stampa effettive):

   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


Si calcola s(1000000)abbastanza rapidamente
mbomb007,

3

Racchetta 187 byte

(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)]))

test:

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

Produzione:

1.028125
1.6275390625
1.5695312499999998
1.5085021972656247
1.4585809230804445
1.4485038772225378
1.4456728475168346

Versione dettagliata:

(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 byte

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

(Traduzione di un codice Matlab di esempio)

Test:

#! /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 byte

$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

Axiom 587 byte

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)

meno golf + numeri

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 comune, 207 byte

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

L'uso reducecon :from-end tevita la necessità di eseguire un lambda intermedio di "inversione dell'espiazione" (sostanzialmente (lambda (x y) (expt y x)), risparmiando 14 byte (12, se si rimuovono gli spazi rimovibili).

Dobbiamo ancora gestire l'overflow del float, ma viene ignore-errorsrestituito un modulo in nilcaso di errore, quindi possiamo utilizzare orper fornire un valore predefinito.

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.