Oto-süper-logaritmayı yapın


18

Pozitif bir tamsayı verilen n ve bir sayı a , n -inci tetrasyon arasında bir olarak tanımlanan bir ^ ( a ^ ( a ^ (... ^ a ))), burada ^ üs (veya güç) temsil eder ve ifade içerir numara bir tam n defa.

Başka bir deyişle, tetrasyon sağ çağrışımlı yinelemeli üslüdür. İçin , n = 4 ve bir = 1.6 tetrasyon 1.6 ^ (1.6 ^ (1.6 ^ 1.6)) olan, ≈ 3,5743.

İle ilgili olarak tetrasyon ters fonksiyonu n olan süper logaritma . Önceki örnekte, 4, 3.5743'ün "süper-baz" 1.6 ile süper logaritmasıdır.

Meydan okuma

Pozitif bir tamsayı Verilen n , bulmak x öyle ki , n süper baz kendisi süper logaritmasidir x . Olduğunu bulmak x öyle ki x ^ ( x ^ ( x ^ (... ^ x ))) (ile x görünen n kez) eşittir n .

kurallar

Program veya işleve izin verilir.

Giriş ve çıkış formatları her zamanki gibi esnektir.

Algoritma teorik olarak tüm pozitif tamsayılar için çalışmalıdır. Pratikte, giriş bellek, zaman veya veri tipi kısıtlamaları nedeniyle maksimum bir değerle sınırlı olabilir. Ancak, kodun 100en az bir dakikadan daha kısa sürede girilebilmesi için çalışması gerekir .

Algoritma teorik olarak sonucu 0.001kesin olarak vermelidir . Pratikte, sayısal hesaplamalarda biriken hatalar nedeniyle çıktı hassasiyeti daha kötü olabilir. Bununla birlikte, çıktı 0.001belirtilen test senaryolarına kadar doğru olmalıdır .

En kısa kod kazanır.

Test senaryoları

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

Referans uygulaması

İşte Matlab / Octave'da bir referans uygulaması ( Ideone'da deneyin ).

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)

Bunun için N = 10verir result = 1.5085.

Aşağıdaki kod, değişken hassasiyetli aritmetik kullanan çıkış hassasiyetinin kontrolüdür :

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

Bu şunu verir:

  • İçin x = 1.5085:y = 10.00173...
  • İçin x = 1.5085 + .001:y = 10.9075
  • Çünkü x = 1.5085 - .001verir y = 9.23248.

böylece 1.5085sahip geçerli bir çözümdür .001hassas.


İlgili . Farklılıklar, buradaki süper logaritmanın (süper-) tabanının sabit olmaması ve sonucun genel olarak bir tamsayı olmamasıdır.
Luis Mendo

İşlev oldukça hızlı bir şekilde birleşiyor gibi görünüyor. Algoritmamız sadece 0.001 dahilinde bir eğri uyumu ise, bu teorik olarak tüm pozitif tamsayılar için çalışıyor mu?
xnor


@KevinCruijssen Matlab'da oldukça hızlı olan ikili aramaya dayanan bir referans uygulamam var.
Yararlıysa

1
Mu xolarak yakınsama nsonsuza yaklaşan?
mbomb007

Yanıtlar:


3

Dyalog APL , 33 25 bayt

⎕IO←0Birçok sistemde varsayılan olan ihtiyaçlar .

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

Teorik olarak tüm tamsayılar için hesaplar, ancak pratik olarak sadece çok küçük olanla sınırlıdır.

TryAPL çevrimiçi!


100 girişinde yeterince hızlı çalışıyor mu?
Greg Martin

@GregMartin Yeterli bellek yok.
Adam

10

Haskell, 55 54 52 bayt

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

Kullanımı:

> s 100
1.445600000000061

@Nimi'ye 1 bayt için teşekkürler!
2x @xnor'a teşekkürler!


1
[ ]!!0yerine head[ ]bir bayt kaydeder
nimi

1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0Haskell'in türlerini kabul etmesini sağlayabilseydiniz daha kısa olurdu.
xnor

@xnor Aslında yazdığımda yinelemeyle oynadım, ancak bir şekilde o zaman daha uzun çıktı
BlackCap

6

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

ES6

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

ES7

**DanTheMan'ın önerdiği şekilde kullanma :

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

Misal

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


ES7 kullanıyorsanız, **yerine kullanabilirsiniz Math.pow.
DanTheMan

4

Mathematica, 40 33 bayt

Neredeyse% 20 tasarruf için murphy sayesinde!

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

Nest[x^#&,1,n]x'in n. tetrasyonunu üretir. Bu nedenle Nest[x^#&,1,#]<#, x'in (giriş) inci tetrasyonunun (giriş) değerinden düşük olup olmadığını test eder. Sadece x = 1'den başlar ve tetrasyon çok büyük olana kadar tekrar tekrar 0.001 ekleriz, sonra son x değerini veririz (böylece cevabın tam değerden daha büyük, ancak 0.001 içinde olması garanti edilir).

Yavaş yavaş öğrendiğim gibi: //.x_:>y/;zveya //.x_/;z:>y"x şablonuyla eşleşen herhangi bir şeyi arayın, ancak yalnızca test z'nin doğru olduğu şeyleri arayın ve sonra y kuralı ile x üzerinde çalışın; hiçbir şey değişene kadar tekrar tekrar". Burada şablon x_sadece "gördüğüm herhangi bir sayı" dır, ancak diğer bağlamlarda daha da kısıtlanabilir.

Giriş en az 45 olduğunda, tetrasyon o kadar hızlı artar ki son adım bir taşma hatasına neden olur; ancak x değeri hala güncellenir ve doğru şekilde çıktılanır. Adım boyutunu 0.001'den 0.0001'e düşürmek, 112'ye kadar girişler için bu sorunu giderir ve önyükleme için daha kesin bir yanıt verir (ve yaklaşık çeyrek saniye içinde hızlı bir şekilde çalışır). Ama bu fazladan bir bayt, unut gitsin!

Orijinal versiyon:

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

Biraz golf oynadı:1//.x_:>x+.001/;Nest[x^#&,1,#]<#&
murphy

@murphy: harika! Yemin ederim ki henüz //.yardım almadan kullanabileceğim noktaya geleceğim :)
Greg Martin

4

J, 39 31 28 bayt

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

Referans uygulamasına dayanmaktadır. Sadece üç ondalık basamak için doğrudur.

@ Adám'ın çözümündeki yöntemi kullanarak 8 bayt kaydedildi .

kullanım

Birden çok giriş / çıkışı biçimlendirmek için kullanılan ekstra komutlar.

   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

açıklama

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

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 çıktısı (gerçek baskı ifadelerini atlama):

   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


s(1000000)Oldukça hızlı hesaplar
mbomb007 16:16

3

Raket 187 bayt

(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 yapmak:

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

Çıktı:

1.028125
1.6275390625
1.5695312499999998
1.5085021972656247
1.4585809230804445
1.4485038772225378
1.4456728475168346

Ayrıntılı sürüm:

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

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

(Örnek Matlab kodunun çevirisi)

Ölçek:

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

$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 bayt

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)

daha az golf edilmiş + sayılar

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

Ortak Lisp, 207 bayt

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

İle kullanmak reduce, :from-end t"ters üs alma" ara lambda (temel olarak (lambda (x y) (expt y x)), 14 bayt tasarruf (çıkarılabilir alanları kaldırırsanız 12)) yapmaktan kaçınır .

Şamandıra taşmasını ele almamız gerekiyor, ancak bir hata oluşursa bir ignore-errorsform döndürülür nil, bu nedenle orvarsayılan bir değer sağlamak için kullanabiliriz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.