자동 슈퍼 로그를 수행


18

양수 주어 N 및 숫자 상기 N 번째 테트 레이션 의 A는 로서 정의된다 ^ ( ^ ( ^ (... ^ ))), 여기서 ^는 지수 (또는 전력)을 나타낸다 및식이 포함 숫자 는 정확히 n 번입니다.

다시 말해, tetration은 right-associative 반복 지수화입니다. 들면 N = 4 = 1.6 테트 레이션 1.6 ^ (1.6 ^ (1.6 ^ 1.6))이다 ≈ 3.5743.

n에 대한 정션의 역함수 는 수퍼 로그 입니다. 이전 예에서 4는 "super-base"1.6이 포함 된 3.5743의 수퍼 로그입니다.

도전

양의 정수를 감안할 때 N , 찾아 X 하도록 n은 슈퍼베이스에서 자체의 슈퍼 로그 인 x가 . 즉, 발견 X 되도록 X ^ ( X ^ ( X ^ (... ^ x가 ))) (와 X가 나타나는 N 회)와 동일 없음 .

규칙

프로그램 또는 기능이 허용됩니다.

입력 및 출력 형식은 평소처럼 유연합니다.

알고리즘은 이론적으로 모든 양의 정수에 대해 작동해야합니다. 실제로, 입력은 메모리, 시간 또는 데이터 유형 제한으로 인해 최대 값으로 제한 될 수 있습니다. 그러나 코드는 100최소 1 분 이내에 입력에 대해 작동해야합니다 .

알고리즘은 이론적으로 결과를 0.001정밀하게 제공해야합니다 . 실제로, 수치 계산에서 누적 오차로 인해 출력 정밀도가 떨어질 수 있습니다. 그러나 0.001표시된 테스트 사례 에 대해 출력이 정확해야합니다 .

가장 짧은 코드가 승리합니다.

테스트 사례

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

참조 구현

Matlab / Octave 의 참조 구현 은 다음과 같습니다 ( 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)

이를 N = 10위해 제공합니다 result = 1.5085.

다음 코드는 가변 정밀도 산술을 사용하여 출력 정밀도를 검사 합니다.

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

이것은 다음을 제공합니다.

  • 의 경우 x = 1.5085:y = 10.00173...
  • 의 경우 x = 1.5085 + .001:y = 10.9075
  • 의 경우 x = 1.5085 - .001가 있습니다 y = 9.23248.

그래서 1.5085있는 유효한 솔루션입니다 .001정밀도.


관련 . 차이점은 여기서 수퍼 로그의 (수퍼)베이스는 고정되어 있지 않으며 결과는 일반적으로 정수가 아닙니다.
— Luis Mendo

함수가 다소 빨리 수렴하는 것처럼 보입니다. 우리의 알고리즘이 0.001 이내의 곡선 맞춤이라면 이론적으로 모든 양의 정수에 대해 작동하는 것으로 간주됩니까?
— xnor

2
wolframalpha는 이미 테스트 사례 6에 문제가 있습니다. " 표준 계산 시간이 초과되었습니다 ... "
— Kevin Cruijssen

@KevinCruijssen 나는 이진 검색을 기반으로 Matlab에 참조 구현이 있는데 이는 상당히 빠릅니다. 도움이된다면 게시 할 수 있습니다
— Luis Mendo

1
음주자 x로 수렴 n무한대에 가까워?
— mbomb007

답변:


3

Dyalog APL , 33 25 바이트

⎕IO←0많은 시스템에서 기본값이 필요 합니다.

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

이론적으로 모든 정수에 대해 계산하지만 실제로 매우 작은 정수로만 제한됩니다.

TryAPL 온라인!


입력 100에서 충분히 빠르게 작동합니까?
— Greg Martin

@GregMartin 메모리가 부족합니다.
— Adám

10

하스켈, 55 54 52 바이트

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

용법:

> s 100
1.445600000000061

1 바이트의 @nimi에게 감사드립니다!
@xnor에게 2를 주셔서 감사합니다!


1
[ ]!!0head[ ]바이트 를 절약하는 대신
— nimi

1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0Haskell이 유형을 받아 들일 수 있다면 더 짧을 것입니다.
— xnor

@xnor 실제로 작성했을 때 반복 작업을했지만 시간이 더 길어졌습니다
— BlackCap

6

자바 스크립트, ES6 : 77 바이트 / ES7 : 57 53 바이트

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=>eval("for(x=2;eval('x**'.repeat(n)+1)>n;)x-=.001")

예

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을 사용하는 경우 **대신 대신 사용할 수 있습니다 Math.pow.
— DanTheMan

4

Mathematica, 40 33 바이트

거의 20 % 절약 된 머피 덕분입니다!

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

Nest[x^#&,1,n]x의 n 번째 tetration을 생성합니다. 따라서 Nest[x^#&,1,#]<#x의 (입력) 네 번째 테트 레이션이 (입력)보다 작은 지 테스트합니다. x = 1에서 시작하여 tetration이 너무 클 때까지 0.001을 반복해서 추가 한 다음 마지막 x 값을 출력합니다 (따라서 정답은 0.001 이내로 정확합니다).

느리게 학습하면서 : //.x_:>y/;z또는 //.x_/;z:>y"템플릿 x와 일치하는 것이지만 테스트 z가 true를 반환하는 것만 찾은 다음 규칙 y에 의해 x에서 작동합니다. x_다른 상황 에서는 템플릿 이 더 제한 될 수 있지만 여기서는 템플릿 이 "모든 숫자"입니다.

입력이 45 이상인 경우 테트라 션이 너무 빠르게 증가하여 마지막 단계에서 오버플로 오류가 발생합니다. 그러나 x 값은 여전히 ​​업데이트되어 올바르게 출력됩니다. 스텝 크기를 0.001에서 0.0001로 줄이면 최대 112 개의 입력에 대해이 문제가 해결되고 부팅에 대한보다 정확한 응답을 제공합니다 (약 1/4 초 안에 빠르게 실행 됨). 그러나 그것은 여분의 바이트이므로 잊지 마십시오!

원본 버전 :

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

약간 골프를 쳤다 :1//.x_:>x+.001/;Nest[x^#&,1,#]<#&
— murphy

@ 머피 : 좋아! 나는 맹세하지만 난 아직 //.도움없이 사용할 수있는 지점에 도달 :)
— 그렉 마틴

4

J, 39 31 28 바이트

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

참조 구현을 기반으로합니다. 소수점 이하 세 자리까지만 정확합니다.

@ Adám 's solution 의 방법을 사용하여 8 바이트를 절약했습니다 .

용법

여러 입력 / 출력을 형식화하는 데 사용되는 추가 명령.

   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

설명

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

파이썬, 184 바이트

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)

테스트 출력 (실제 인쇄 문 생략) :

   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)매우 빠르게 계산
— mbomb007

3

라켓 187 바이트

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

테스트 :

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

산출:

1.028125
1.6275390625
1.5695312499999998
1.5085021972656247
1.4585809230804445
1.4485038772225378
1.4456728475168346

자세한 버전 :

(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

펄 6 , 42 바이트

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

(예 : Matlab 코드 번역)

테스트:

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

my &code = {(0,.0001…2).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 바이트

$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

공리 587 바이트

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)

덜 골프 + 숫자

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

공통 리스프, 207 바이트

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

reducewith를 사용 :from-end t하면 "반전 지수화"중간 람다 (기본적으로 (lambda (x y) (expt y x))14 바이트 (이동식 공간을 제거하는 경우 12) 절약) 를 수행 할 필요가 없습니다 .

여전히 float overflow를 처리해야하지만 오류가 발생하면 ignore-errors폼이 반환 nil되므로 or기본값을 제공하는 데 사용할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.