Làm siêu logarit tự động


18

Cho một số nguyên dương n và một số một , các n -thứ tetration của một được định nghĩa là một ^ ( một ^ ( một ^ (... ^ một ))), nơi ^ biểu lũy thừa (hoặc điện) và biểu thức chứa số a chính xác n lần.

Nói cách khác, tetration là lũy thừa lặp lại liên kết phải. Dành cho n = 4 và a = 1.6 thì phép hóa là 1.6 ^ (1.6 ^ (1.6 ^ 1.6)) 3.5743.

Các chức năng nghịch đảo của tetration đối với nsiêu logarit . Trong ví dụ trước, 4 là siêu logarit của 3,5743 với "siêu cơ sở" 1.6.

Các thách thức

Cho một số nguyên dương n , tìm x sao cho n là siêu logarit của chính nó trong siêu cơ sở x . Nghĩa là tìm x sao cho x ^ ( x ^ ( x ^ (... ^ x ))) (với x xuất hiện n lần) bằng n .

Quy tắc

Chương trình hoặc chức năng được phép.

Định dạng đầu vào và đầu ra linh hoạt như bình thường.

Thuật toán nên hoạt động trên lý thuyết cho tất cả các số nguyên dương. Trong thực tế, đầu vào có thể bị giới hạn ở giá trị tối đa do hạn chế về bộ nhớ, thời gian hoặc loại dữ liệu. Tuy nhiên, mã phải hoạt động cho các đầu vào lên đến100 thiểu trong ít hơn một phút.

Các thuật toán về lý thuyết nên đưa ra kết quả với 0.001độ chính xác. Trong thực tế, độ chính xác đầu ra có thể tồi tệ hơn do lỗi tích lũy trong tính toán số. Tuy nhiên, đầu ra phải chính xác cho đến 0.001các trường hợp thử nghiệm được chỉ định.

Mã ngắn nhất sẽ thắng.

Các trường hợp thử nghiệm

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

Thực hiện tham khảo

Đây là một triển khai tham chiếu trong Matlab / Octave (thử tại 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)

Đối với N = 10điều này choresult = 1.5085 .

Đoạn mã sau là kiểm tra độ chính xác đầu ra, sử dụng số học có độ chính xác thay đổi:

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

Điều này mang lại:

  • Dành cho x = 1.5085:y = 10.00173...
  • Dành cho x = 1.5085 + .001:y = 10.9075
  • Cho x = 1.5085 - .001nó cho y = 9.23248.

như vậy 1.5085là một giải pháp hợp lệ với .001độ chính xác.


Liên quan . Sự khác biệt là cơ sở (siêu) của siêu logarit ở đây không cố định và kết quả không phải là một số nguyên nói chung.
Luis Mendo

Có vẻ như chức năng hội tụ khá nhanh. Nếu thuật toán của chúng tôi chỉ đơn giản là một đường cong phù hợp trong phạm vi 0,001, thì điều đó có được tính là hoạt động trên lý thuyết cho tất cả các số nguyên dương không?
xnor


@KevinCruijssen Tôi có một triển khai tham chiếu trong Matlab dựa trên tìm kiếm nhị phân rất nhanh. Tôi có thể đăng nó nếu điều đó hữu ích
Luis Mendo

1
Liệu xhội tụ như ncách tiếp cận vô cùng?
mbomb007

Câu trả lời:


3

APL Dyalog , 33 25 byte

Nhu cầu ⎕IO←0được mặc định trên nhiều hệ thống.

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

Về mặt lý thuyết tính toán cho tất cả các số nguyên, nhưng thực tế chỉ giới hạn ở một số rất nhỏ.

Dùng thử trực tuyến!


Nó có hoạt động đủ nhanh trên 100 đầu vào không?
Greg Martin

@GregMartin Không đủ bộ nhớ.
Adám

10

Haskell, 55 54 52 byte

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

Sử dụng:

> s 100
1.445600000000061

Cảm ơn @nimi cho 1 byte!
Cảm ơn @xnor cho 2!


1
[ ]!!0thay vì head[ ]tiết kiệm một byte
nimi

1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0sẽ ngắn hơn nếu bạn có thể khiến Haskell chấp nhận các loại của nó.
xnor

@xnor Tôi đã chơi xung quanh với iterate khi tôi viết nó thực sự, nhưng bằng cách nào đó nó bật ra lâu hơn vào thời điểm đó
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

Sử dụng **theo đề xuất của DanTheMan:

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

Thí dụ

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


Nếu bạn sử dụng ES7, bạn có thể sử dụng **thay vì Math.pow.
DanTheMan

4

Toán học, 40 33 byte

Nhờ mur mur cho một khoản tiết kiệm gần 20%!

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

Nest[x^#&,1,n]tạo ra phép biến đổi thứ n của x. Vì vậy, Nest[x^#&,1,#]<#kiểm tra xem phép biến đổi (đầu vào) của x có nhỏ hơn (đầu vào) hay không. Chúng ta chỉ cần bắt đầu với x = 1 và thêm 0,001 liên tục cho đến khi phép chia quá lớn, sau đó xuất giá trị x cuối cùng (vì vậy câu trả lời được đảm bảo lớn hơn giá trị chính xác, nhưng trong phạm vi 0,001).

Khi tôi đang dần học hỏi: //.x_:>y/;zhoặc//.x_/;z:>y có nghĩa là "tìm kiếm bất cứ thứ gì phù hợp với mẫu x, nhưng chỉ những thứ mà phép thử z trả về đúng; và sau đó hoạt động trên x theo quy tắc y; lặp đi lặp lại cho đến khi không có gì thay đổi". Ở đây mẫu x_chỉ là "bất kỳ số nào tôi thấy", mặc dù trong các bối cảnh khác, nó có thể bị hạn chế hơn nữa.

Khi đầu vào ít nhất là 45, phép tetination tăng nhanh đến mức bước cuối cùng gây ra lỗi tràn; nhưng giá trị của x vẫn được cập nhật và đầu ra chính xác. Việc giảm kích thước bước từ 0,001 xuống 0,0001 khắc phục sự cố này cho đầu vào lên tới 112 và đưa ra câu trả lời chính xác hơn để khởi động (và vẫn chạy nhanh, trong khoảng một phần tư giây). Nhưng đó là một byte thêm, vì vậy hãy quên điều đó!

Phiên bản gốc:

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

Chơi gôn một chút:1//.x_:>x+.001/;Nest[x^#&,1,#]<#&
murumb

@murphy: tuyệt! Tôi thề tôi sẽ đến điểm mà tôi có thể sử dụng //.mà không cần trợ giúp :)
Greg Martin

4

J, 39 31 28 byte

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

Dựa trên việc thực hiện tham khảo. Nó chỉ chính xác đến ba chữ số thập phân.

Đã lưu 8 byte bằng phương thức từ giải pháp của @ Adám .

Sử dụng

Các lệnh bổ sung được sử dụng để định dạng nhiều đầu vào / đầu ra.

   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

Giải trình

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

Kiểm tra đầu ra (bỏ qua các báo cáo in thực tế):

   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


Nó tính toán s(1000000)khá nhanh
mbomb007

3

Vợt 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)]))

Kiểm tra:

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

Đầu ra:

1.028125
1.6275390625
1.5695312499999998
1.5085021972656247
1.4585809230804445
1.4485038772225378
1.4456728475168346

Phiên bản chi tiết:

(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$_}}

(Bản dịch mã Matlab ví dụ)

Kiểm tra:

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

Tiên đề 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)

ít đánh gôn + số

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 thông thường, 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))

Sử dụng reducevới :from-end tđể tránh sự cần thiết phải thực hiện lambda trung gian "đảo ngược lũy thừa" (về cơ bản (lambda (x y) (expt y x)), tiết kiệm 14 byte (12, nếu bạn loại bỏ các khoảng trống có thể tháo rời).

Chúng tôi vẫn cần xử lý tràn float, nhưng một ignore-errorsbiểu mẫu trả về nilnếu xảy ra lỗi, vì vậy chúng tôi có thể sử dụng orđể cung cấp một giá trị mặc định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.