Calcola il super-logaritmo


29

Questa dovrebbe essere una sfida semplice.

Dato un numero n >= 0, genera il super-logaritmo (o il log *, log-star o logaritmo iterato , che sono equivalenti poiché nnon è mai negativo per questa sfida.) nDi.

log * (n): = {0 se n <= 1;  1 + registro * (registro (n)) se n> 1}

Questa è una delle due funzioni inverse rispetto alla tetrazione . L'altro è il super-root , che si trova in una domanda correlata .

Esempi

Input       Output
0           0
1           0
2           1
3           2
4           2
...
15          2
16          3
...
3814279     3
3814280     4

Regole

  • Non è necessario supportare i decimali, anche se è possibile.
  • Devi supportare almeno l'input 3814280 = ceiling(e^e^e).
  • Non è possibile codificare i valori come 3814280. (Il tuo programma deve teoricamente supportare numeri più alti.) Voglio implementare un algoritmo.
  • Il codice più corto vince.

OEIS correlato


Risposte:


14

Gelatina , 8 byte

ÆlÐĿĊḊi1

Provalo online! o verifica tutti i casi di test .

sfondo

Iniziamo prendendo successivamente logaritmi naturali dell'input e dei risultati successivi fino a quando il risultato non cambia più. Questo funziona perché l'estensione del logaritmo naturale al piano complesso ha un punto fisso ; se z = e -W (-1) ≈ 0,318 + 1.337i - dove W indica la funzione Lambert W - abbiamo log (z) = z .

Per l'input n , dopo aver calcolato [n, log (n), log (log (n)), ..., z] , applichiamo innanzitutto la funzione soffitto a ciascuno dei risultati. L'implementazione di Jelly ( Ċ) in realtà calcola invece la parte immaginaria del numero complesso , ma non ci interessa comunque.

Una volta che il k esima applicazione di registro produce un valore inferiore o uguale a 1 , Ċrestituirà 1 per la prima volta. L'indice basato su 0 di quel primo 1 è il risultato desiderato.

L'implementazione semplice (indice basato sul calcolo 1, decremento) non riesce a causa del caso limite 0 , che non ha un 1 nel suo elenco di logaritmi. In effetti, per l'ingresso 0 , la sequenza dei logaritmi è

[0, None]

Questo perché il logaritmo di Jelly ( Æl) è sovraccarico; prima prova math.log(logaritmo reale), poi cmath.log(logaritmo complesso), e infine "si arrende" e ritorna None. Fortunatamente, Ċè sovraccarico in modo simile e restituisce semplicemente argomento se non può arrotondare o prendere una parte immaginaria.

Allo stesso modo, l'ingresso 1 ritorna

[1, 0, None]

che può creare problemi in altri approcci che coinvolgono o meno Ċ.

Un modo per risolvere questo problema è applicare (dequeue; rimuove il primo elemento) all'array di logaritmi. Questa mappa

0ÆlÐĿ -> [0, None]    -> [None]
1ÆlÐĿ -> [1, 0, None] -> [0, None]

quindi nessuna delle liste ha un 1 ora. In questo modo, trovando l'indice del primo 1 restituirà 0 (non trovato), che è l'uscita desiderata per gli ingressi 0 e 1 .

Come funziona

ÆlÐĿĊḊi1  Main link. Argument: n (non-negative integer)

  ÐĿ      Apply the following link until the results are no longer unique.
Æl          Natural logarithm.
          Return the array of all unique results.
    Ċ     Round all resulting real numbers up to the nearest integer. This takes
          the imaginary part of complex numbers and does nothing for non-numbers.
     Ḋ    Dequeue; remove the first item (n) of the array of results.
      i1  Find the first index of 1 (0 if not found).

Questo è uno dei soli tre atomi in Jelly che sono sovraccarichi in modo non ovvio.


11

Gelatina , 9 byte

Æl>1$пL’

Provalo online!

Suite di test.(Leggermente modificato.)

Spiegazione

Æl>1$пL’
     п    while loop, collect all intermediate results.
  >1$      condition: z>1
Æl         body: natural logarithm.
       L   length of the array containing all intermediate results,
           meaning number of iterations
        ’  minus one.


7

Javascript, 45 27 26 byte

l=a=>a>1&&1+l(Math.log(a))

Ecco la suite di test (3 ° giro)

Grazie @LeakyNun per il salvataggio di 1 byte con condizionale e quindi la conversione della funzione in lambda, e @Neil per la segnalazione di false è ok valore di ritorno per <= 1 (il test modificato è stato == invece di ===)


Lo stavo facendo senza es6, ma sì, sarebbe 1 byte più corto, grazie.
CShark,

Perché non dovresti usare lambda?
Leaky Nun,

nessuna buona ragione, non l'ho usato così tanto, quindi non è il mio primo istinto
CShark

Apparentemente ci è permesso di restituire falseinvece di 0 (in quanto si converte automaticamente in 0 in un'espressione intera) nel qual caso è possibile eliminare |0.
Neil,

Ciò consentirebbe di risparmiare 1 byte, ma cosa intendi con "si converte automaticamente in 0"? Che cos'è"?
CShark,

6

Mathematica, 21 byte

If[#>1,1+#0@Log@#,0]&

Funzione anonima ricorsiva. Prende un numero intero come input e restituisce il suo super-logaritmo come output. Utilizza solo la definizione fornita.


3
In realtà ho guardato in anticipo per vedere se c'era un built-in. Sono stato sorpreso quando non c'era. : D
mbomb007,




4

Python 3, 45 byte

import math
s=lambda x:x>1and-~s(math.log(x))

Per x <= 1, questo ritorna False(che è == 0in Python).


Sì, Falsepuò essere utilizzato per 0.
mbomb007,

Inoltre, hai battuto la mia ingenua implementazione (usando andpiuttosto che if else). Grats.
mbomb007,

4

05AB1E, 16 13 byte

[Dî2‹#¼žr.n]¾

Spiegazione

              # implicit input n
[          ]  # infinite loop
 Dî2‹#        # break if n rounded up is less than 2
      ¼       # else, increase counter
       žr.n   # set next n = log(n)
            ¾ # push counter and implicitly print

Provalo online


3

MATL , 15 12 byte

0`ZetG>~}x@q

Provalo online! Oppure verifica tutti i casi di test (versione leggermente modificata per gestire più input).

Come funziona

A partire da 0, applica esponenziazione iterata fino a superare l'input. L'output è il numero di iterazioni meno 1.

0       % Push 0
`       % Do...while loop
  Ze    %   Exponential
  t     %   Duplicate
  G     %   Push input
  >~    %   Is current value less than or equal to the input? If so: next iteration
}       % Finally (code executed at the end of the last iteration)
  x     %   Delete
  @q    %   Iteration index minus 1
        % Implicitly end loop
        % Implicitly display stack

3

J , 21 19 18 16 byte

Hai salvato 2 byte su Leaky Nun, 1 byte su Galen Ivanov e 2 byte su FrownyFrog!

2#@}.(0>.^.)^:a:

Provalo online!

Casi test

ls =: >:@$:@^.`0:@.(<:&1)
   ls 0
0
   ls 1
0
   ls 2
1
   ls 3
2
   ls 4
2
   ls 15
2
   ls 16
3
   ls 3814280
4

Ecco la mia soluzione a 18 byte: 2#@}.^.^:(0<])^:a:(Ho iniziato a sovvertire quello che si è rivelato essere un duplice problema).
Galen Ivanov

2#@}.(0>.^.)^:a:sembra funzionare.
FrownyFrog

Non sono sicuro che sia equivalente però.
FrownyFrog


2

MATLAB / Ottava, 44 byte

function a=g(n);a=0;if n>1;a=1+g(log(n));end

Ho provato a fare tutto come un'unica funzione anonima, ma ho dimenticato che MATLAB / Octave continua a valutare le espressioni anche se sono moltiplicate per un valore booleano falso (zero):

f=@(n)(n>1)*(1+f(log(n)))


Sì, sarebbe bello avere un prodotto in corto circuito :-)
Luis Mendo,

2

R, 38 37 byte

f=function(x)if(x>1)1+f(log(x))else 0

Grazie @ user5957401 per il byte extra!

Casi test:

> f(0)
[1] 0
> f(1)
[1] 0
> f(2)
[1] 1
> f(3)
[1] 2
> f(4)
[1] 2
> f(3814279)
[1] 3
> f(3814280)
[1] 4

Penso che puoi salvare un byte usando un'istruzione letterale if, else. cioè if(x>1)1+f(log(x))else 0è più corto di un byte.
user5957401

2

R , 34 byte

f=pryr::f(`if`(n>1,1+f(log(n)),0))

Provalo online!

È possibile un approccio non ricorsivo: 36 byte e accetta input dallo stdin.

n=scan()
while((n=log(n))>0)F=F+1
+F

2

Java 7, 47 byte

int c(double n){return n>1?1+c(Math.log(n)):0;}

Provalo online.

Il metodo ricorsivo di stile Java 7 sopra è 2 byte più corto di un lambda iterativo in stile Java 8:

n->{int c=0;for(;n>1;c++)n=Math.log(n);return c;}

Provalo online.

Spiegazione:

int c(double n){      // Method with double parameter and integer return-type
  return n>1?         //  If the input is larger than 1:
    1+                //   Return 1 +
      c(Math.log(n))  //   A recursive call with log(input)
   :                  //  Else:
    0;                //   Return 0 instead

n->{                  // Method with double parameter and integer return-type
  int c=0;            //  Create a counter, starting at 0
  for(;n>1;           //  Loop as long as the input is still larger than 1:
    c++)              //   Increase the counter by 1
    n=Math.log(n);    //   And update the input to log(input)
  return c;}          //  After the loop: return the counter as result

Potresti accorciarlo con un lambda Java 8.
mbomb007,

@ mbomb007 tre anni dopo, ahah (a quel tempo ero solo golfista di codice in Java 7), ma per rispondere ancora alla tua domanda: no, purtroppo un lambda Java 8 è 2 byte più lungo del metodo ricorsivo. L'ho aggiunto alla mia risposta e ho anche aggiunto una spiegazione.
Kevin Cruijssen,

Quindi non puoi fare lambda ricorsive?
mbomb007,

@ mbomb007 No, purtroppo in Java no. In Python, JavaScript e credo anche in C # .NET, sono possibili lambda ricorsive, ma in Java non per qualche motivo ..
Kevin Cruijssen

1

Emacs Lisp, 38 byte

(defun l(n)(if(> n 1)(1+(l(log n)))0))

Casi test:

(mapcar 'l '(0 1 2 3 4 15 16 3814279 3814280))
;; (0 0 1 2 2 2 3 3 4)

1

Gelatina , 8 byte

-Ælß$Ị?‘

Implementazione diretta della definizione. Provalo online! o verifica tutti i casi di test .

Come funziona

-Ælß$Ị?‘  Main link. Argument: x

     Ị    Insignificant; test if |x| ≤ 1.
      ?   If the result is 1:
-           Return -1.
          Else:
   $        Execute the monadic chain formed by the two links to the left.
Æl            Apply natural logarithm to x.
  ß           Recursively call the main link.
       ‘  Increment the result.

1

Perl 5, 35 byte

Molto semplice, richiede -M5.016(che è gratuito) per abilitare la __SUB__parola chiave per la ricorsione anonima.

sub{$_[0]>1?1+__SUB__->(log pop):0}

Un'altra alternativa è

sub{$_[0]>1?1+__SUB__->(log pop):0}

che è di 34 byte e fornisce lo stesso output per tutti gli input> 1, ma restituisce lo speciale valore falso per gli input <= 1. False è numericamente uguale a zero, ma viene stampato come "" (stringa vuota), quindi probabilmente non lo fa ' qualificare.


Bella risposta. Puoi vincere 1 byte facendo sub{($_=pop)>1?1+__SUB__->(log):0}però
Dada,

1

CJam (16 byte)

rd{_1>}{_ml}w],(

Demo online

Semplice ciclo while con pre-condizione. (Quello che voglio davvero qui è un'operazione spiegata in stile Golfscript, ma CJam non ne ha una, e il punto fluttuante in GolfScript è disordinato e per nulla golfico).


A parte questo, questa è la mia 80a risposta in matematica e oggi mi sono guadagnato il mio secondo badge tag.
Peter Taylor,


1

Racchetta, 61 byte

(λ(x)(letrec([a(λ(b)(if(> b 1)(+ 1 (a(log b)))0))])(a x)))

1

Acero, 32,30 29 byte

f:=x->`if`(x>1,1+f(log(x)),0)

Casi test:

> f(0.);
  0
> f(1.);
  0
> f(2.);
  1
> f(3.);
  2
> f(4.);
  2
> f(3814279.);
  3
> f(3814280.);
  4

1

R, 36 byte

Approccio leggermente diverso da Plannapus

->n;a=0;while(n>1){a=a+1;n=log(n)};a

Utilizza un'assegnazione corretta per eseguire il codice, quindi il numero desiderato deve precederlo. vale a dire

10->n;a=0;while(n>1){a=a+1;n=log(n)};a

0

Mathematica, 29 byte

Semplice come l'inferno e funziona per input comicamente grandi e negativi:

f[x_]:=If[x>1,1+f[Log[x]],0]

enter image description here



0

Perl 6 , 21 byte

{($_,*.log...1>=*)-1}

Provalo online!

L'espressione tra parentesi è una sequenza. $_, l'argomento della funzione, è il primo elemento. *.loggenera ogni elemento successivo prendendo il registro dell'elemento precedente. La sequenza continua fino a quando la condizione finale 1 >= *, è vera: 1 è maggiore o uguale all'elemento corrente. Sottraendo 1 dalla sequenza lo si costringe a un numero: la sua lunghezza.

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.