Lakukan auto-super-logaritma

18

Mengingat bilangan bulat positif n dan sejumlah satu , yang n th tetration dari sebuah didefinisikan sebagai suatu ^ ( a ^ ( a ^ (... ^ a ))), di mana ^ menunjukkan exponentiation (atau kekuasaan) dan ekspresi berisi angka yang tepat n kali.

Dengan kata lain, tetrasi adalah eksponensiasi iterasi yang diasosiasikan dengan benar. Untuk n = 4 dan a = 1.6 tetrasi adalah 1.6 ^ (1.6 ^ (1.6 ^ 1.6)) ≈ 3.5743.

Fungsi kebalikan dari tetrasi terhadap n adalah super-logaritma . Pada contoh sebelumnya, 4 adalah super-logaritma 3.5743 dengan "super-base" 1.6.

Tantangan

Dengan bilangan bulat positif n , temukan x sedemikian rupa sehingga n adalah super-logaritma itu sendiri dalam super-basis x . Yaitu, temukan x sedemikian sehingga x ^ ( x ^ ( x ^ (... ^ x )))) (dengan x muncul n kali) sama dengan n .

Aturan

Program atau fungsi diizinkan.

Format input dan output fleksibel seperti biasa.

Algoritme secara teoritis harus bekerja untuk semua bilangan bulat positif. Dalam praktiknya, input mungkin terbatas pada nilai maksimum karena batasan memori, waktu atau tipe data. Namun, kode harus bekerja untuk input hingga 100setidaknya dalam waktu kurang dari satu menit.

Algoritme secara teoritis harus memberikan hasil dengan 0.001presisi. Dalam praktiknya, ketepatan output mungkin lebih buruk karena akumulasi kesalahan dalam perhitungan numerik. Namun, hasilnya harus akurat hingga 0.001untuk kasus uji yang ditunjukkan.

Kode terpendek menang.

Uji kasus

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

Implementasi referensi

Berikut ini adalah implementasi referensi di Matlab / Oktaf (coba di 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)

Untuk N = 10ini memberi result = 1.5085.

Kode berikut adalah pemeriksaan dari presisi keluaran, menggunakan aritmatika presisi-variabel:

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

Ini memberi:

  • Untuk x = 1.5085:y = 10.00173...
  • Untuk x = 1.5085 + .001:y = 10.9075
  • Untuk x = 1.5085 - .001itu memberi y = 9.23248.

begitu 1.5085juga solusi yang valid dengan .001presisi.

Luis Mendo
sumber
Terkait . Perbedaannya adalah bahwa basis (super-) super-logaritma di sini tidak tetap, dan hasilnya bukan bilangan bulat secara umum.
Luis Mendo
Sepertinya fungsi menyatu agak cepat. Jika algoritme kami hanyalah kesesuaian kurva yang berada dalam 0,001, apakah itu dianggap secara teoritis berfungsi untuk semua bilangan bulat positif?
xnor
2
Hmm, wolframalpha sudah mengalami masalah dengan test case 6 .. " Waktu komputasi standar melebihi ... "
Kevin Cruijssen
@KevinCruijssen Saya memiliki implementasi referensi di Matlab berdasarkan pencarian biner yang cukup cepat. Saya dapat mempostingnya jika itu membantu
Luis Mendo
1
Apakah xkonvergen nmendekati infinity?
mbomb007

Jawaban:

3

Dyalog APL , 33 25 byte

Kebutuhan ⎕IO←0yang standar pada banyak sistem.

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

Secara teoritis menghitung untuk semua bilangan bulat, tetapi praktis terbatas pada yang sangat kecil saja.

TryAPL online!

Adm
sumber
Apakah kerjanya cukup cepat pada input 100?
Greg Martin
@GregMartin Tidak cukup memori.
Adám
10

Haskell, 55 54 52 byte

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

Pemakaian:

> s 100
1.445600000000061

Terima kasih kepada @nimi untuk 1 byte!
Terima kasih kepada @xnor untuk 2!

BlackCap
sumber
1
[ ]!!0bukannya head[ ]menyimpan byte
nimi
1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0akan lebih pendek jika Anda bisa membuat Haskell menerima tipenya.
xnor
@ xnor Saya bermain-main dengan iterate ketika saya menulisnya sebenarnya, tapi entah bagaimana ternyata lebih lama pada waktu itu
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

Menggunakan **seperti yang disarankan oleh DanTheMan:

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

Contoh

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

Arnauld
sumber
Jika Anda menggunakan ES7, Anda bisa menggunakan **sebagai gantinya Math.pow.
DanTheMan
4

Mathematica, 40 33 byte

Berkat murphy untuk penghematan hampir 20%!

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

Nest[x^#&,1,n]menghasilkan tetrasi ke-n x. Jadi Nest[x^#&,1,#]<#menguji apakah (input) tetrasi x kurang dari (input). Kita cukup mulai dari x = 1 dan menambahkan 0,001 berulang kali hingga tetrasinya terlalu besar, kemudian mengeluarkan nilai x terakhir (jadi jawabannya dijamin lebih besar dari nilai yang tepat, tetapi dalam 0,001).

Karena saya perlahan-lahan belajar: //.x_:>y/;zatau //.x_/;z:>yberarti "mencari apa pun yang cocok dengan templat x, tetapi hanya hal-hal di mana tes z mengembalikan true; dan kemudian beroperasi pada x oleh aturan y; berulang kali sampai tidak ada perubahan". Di sini templatnya x_hanyalah "angka apa pun yang saya lihat", meskipun dalam konteks lain hal itu dapat dibatasi lebih lanjut.

Ketika input minimal 45, tetrasi meningkat begitu cepat sehingga langkah terakhir menyebabkan kesalahan overflow; tetapi nilai x masih diperbarui dan dikeluarkan dengan benar. Mengurangi ukuran langkah dari 0,001 menjadi 0,0001 memperbaiki masalah ini untuk input hingga 112, dan memberikan jawaban yang lebih tepat untuk mem-boot (dan masih berjalan cepat, dalam sekitar seperempat detik). Tapi itu satu byte tambahan, jadi lupakan itu!

Versi asli:

x=1;(While[Nest[x^#&,1,#]<#,x+=.001];x)&
Greg Martin
sumber
Golf sedikit:1//.x_:>x+.001/;Nest[x^#&,1,#]<#&
murphy
@murphy: bagus! Saya bersumpah saya belum akan sampai pada titik di mana saya dapat menggunakan //.tanpa bantuan :)
Greg Martin
4

J, 39 31 28 byte

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

Berdasarkan implementasi referensi. Hanya akurat untuk tiga tempat desimal.

Disimpan 8 byte menggunakan metode dari solusi @ Adám .

Pemakaian

Perintah tambahan digunakan untuk memformat beberapa 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

Penjelasan

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

Hasil uji (melewatkan pernyataan cetak yang sebenarnya):

   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
Vatine
sumber
bermain golf
Itu menghitung s(1000000)cukup cepat
mbomb007
3

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

Pengujian:

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

Keluaran:

1.028125
1.6275390625
1.5695312499999998
1.5085021972656247
1.4585809230804445
1.4485038772225378
1.4456728475168346

Versi detail:

(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)]))
juga
sumber
2

Perl 6 , 42 byte

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

(Terjemahan kode Matlab misalnya)

Uji:

#! /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
Brad Gilbert b2gills
sumber
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;
Jörg Hülsermann
sumber
1

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

lebih sedikit nomor + golf

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
RosLuP
sumber
1

Gangguan Umum, 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))

Menggunakan reducedengan :from-end tmenghindari perlunya melakukan lambda antara "membalikkan eksponensial" (pada dasarnya (lambda (x y) (expt y x)), menghemat 14 byte (12, jika Anda menghapus ruang yang dapat dilepas).

Kita masih perlu menangani float overflow, tetapi suatu ignore-errorsformulir kembali niljika terjadi kesalahan, sehingga kita dapat menggunakan oruntuk memberikan nilai default.

Vatine
sumber