ทำลอการิทึมอัตโนมัติสุด


18

ป.ร. ให้ไว้เป็นจำนวนเต็มบวกnและหมายเลขที่n -th tetrationของถูกกำหนดให้เป็น^ ( ^ ( ^ ( ... ^ ))) ที่^หมายถึงการยกกำลัง (หรือพลังงาน) และการแสดงออกมี จำนวนว่าnครั้ง

กล่าวอีกนัยหนึ่งการทำซ้ำก็คือการยกกำลังซ้ำที่เชื่อมโยงกันอย่างถูกต้อง สำหรับn = 4 และa = 1.6 การกรองคือ 1.6 ^ (1.6 ^ (1.6 ^ 1.6)) ≈ 3.5743

ฟังก์ชั่นผกผันของ tetration ด้วยความเคารพnเป็นซุปเปอร์ลอการิทึม ในตัวอย่างก่อนหน้านี้ 4 เป็นลอการิทึม super ของ 3.5743 กับ "super-base" 1.6

ความท้าทาย

ป.ร. ให้ไว้เป็นจำนวนเต็มบวกnค้นหาxดังกล่าวที่nเป็นซุปเปอร์ลอการิทึมของตัวเองในซุปเปอร์ฐานx นั่นคือหาxเช่นว่าx ^ ( x ^ ( x ^ ( ... ^ x ))) (มีxปรากฏnครั้ง) เท่ากับn

กฎระเบียบ

อนุญาตให้ใช้โปรแกรมหรือฟังก์ชั่น

รูปแบบอินพุตและเอาต์พุตมีความยืดหยุ่นตามปกติ

อัลกอริทึมควรใช้ทฤษฎีสำหรับจำนวนเต็มบวกทั้งหมด ในทางปฏิบัติอินพุตอาจถูก จำกัด ให้มีค่าสูงสุดเนื่องจากข้อ จำกัด ด้านหน่วยความจำเวลาหรือชนิดข้อมูล อย่างไรก็ตามรหัสจะต้องใช้งานได้กับอินพุต100อย่างน้อยในเวลาน้อยกว่าหนึ่งนาที

อัลกอริทึมควรให้ผลลัพธ์อย่าง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 = 10result = 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 - .001y = 9.23248

ดังนั้นจึง1.5085เป็นทางออกที่ถูกต้องด้วย.001ความแม่นยำ


ที่เกี่ยวข้อง ความแตกต่างคือฐาน (super-) ของ super-logarithm ที่นี่ไม่คงที่และผลลัพธ์ไม่ได้เป็นจำนวนเต็มโดยทั่วไป
Luis Mendo

ดูเหมือนว่าฟังก์ชั่นจะมาบรรจบกันอย่างรวดเร็ว หากอัลกอริทึมของเราเป็นเส้นโค้งที่พอดีที่อยู่ภายใน 0.001 นั่นจะนับว่าเป็นการทำงานเชิงทฤษฎีสำหรับจำนวนเต็มบวกทั้งหมดหรือไม่
xnor

2
อืม wolframalpha มีปัญหากับกรณีทดสอบ 6 แล้ว .. " เกินเวลาในการคำนวณมาตรฐาน ... "
Kevin Cruijssen

@KevinCruijssen ฉันมีการใช้งานอ้างอิงใน Matlab ตามการค้นหาแบบไบนารีซึ่งรวดเร็วพอสมควร ฉันสามารถโพสต์ได้หากเป็นประโยชน์
หลุยส์เมนโด

1
ไม่xบรรจบกันเป็นnวิธีการที่อินฟินิตี้?
mbomb007

คำตอบ:


3

Dyalog APL , 33 25 ไบต์

ความต้องการ⎕IO←0ซึ่งเป็นค่าเริ่มต้นในหลาย ๆ ระบบ

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

ในทางทฤษฎีคำนวณสำหรับจำนวนเต็มทั้งหมด แต่ในทางปฏิบัติถูก จำกัด ให้มีขนาดเล็กมากเท่านั้น

ลองใช้ออนไลน์!


มันทำงานเร็วพอกับอินพุต 100 หรือไม่
Greg Martin

@GregMartin หน่วยความจำไม่เพียงพอ
อดัม

10

Haskell, 55 54 52 ไบต์

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

การใช้งาน:

> s 100
1.445600000000061

ขอบคุณ @nimi สำหรับ 1 ไบต์!
ขอบคุณ @xnor สำหรับ 2!


1
[ ]!!0แทนการhead[ ]บันทึกไบต์
nimi

1
s n=[x|x<-[2,1.9999..],n>iterate(x**)1!!n]!!0จะสั้นลงหากคุณสามารถให้ Haskell ยอมรับประเภทของมันได้
xnor

@ xnor ฉันเล่นรอบกับ iterate เมื่อฉันเขียนมันจริง แต่อย่างใดมันเปิดออกอีกต่อไปในเวลา
BlackCap

6

Javascript, 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 ไบต์

ขอบคุณ murphy สำหรับการประหยัดเกือบ 20%!

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

Nest[x^#&,1,n]ก่อให้เกิดการเตตที่ n ของ x ดังนั้นNest[x^#&,1,#]<#ทดสอบว่าการป้อนข้อมูล (อินพุต) ของ x น้อยกว่า (อินพุต) หรือไม่ เราเริ่มต้นที่ x = 1 และเพิ่ม 0.001 ซ้ำ ๆ จนกระทั่งการกรองมีขนาดใหญ่เกินไปจากนั้นจึงส่งออกค่า x สุดท้าย (ดังนั้นคำตอบจะรับประกันว่าจะมีค่ามากกว่าค่าที่แน่นอน แต่ภายใน 0.001)

ขณะที่ฉันเรียนรู้อย่างช้า ๆ : //.x_:>y/;zหรือ//.x_/;z:>yหมายถึง "มองหาสิ่งที่ตรงกับเทมเพลต x แต่เฉพาะสิ่งที่การทดสอบ z คืนค่าจริงแล้วดำเนินการกับกฎ x โดยทำซ้ำ ๆ จนกระทั่งไม่มีอะไรเปลี่ยนแปลง" ที่นี่แม่แบบx_เป็นเพียง "หมายเลขใด ๆ ที่ฉันเห็น" แม้ว่าในบริบทอื่น ๆ มันอาจถูก จำกัด เพิ่มเติม

เมื่ออินพุทอย่างน้อย 45 การไตเตรทจะเพิ่มขึ้นอย่างรวดเร็วจนขั้นตอนสุดท้ายทำให้เกิดข้อผิดพลาดมากเกิน แต่ค่าของ x ยังคงได้รับการปรับปรุงและส่งออกอย่างถูกต้อง การลดขนาดขั้นตอนจาก 0.001 ถึง 0.0001 แก้ไขปัญหานี้สำหรับอินพุตสูงสุด 112 และให้คำตอบที่แม่นยำยิ่งขึ้นสำหรับการบูต (และยังคงทำงานได้อย่างรวดเร็วในเวลาประมาณหนึ่งในสี่วินาที) แต่นั่นเป็นหนึ่งไบต์พิเศษดังนั้นอย่าลืม!

รุ่นเดิม:

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

ขึ้นอยู่กับการดำเนินการอ้างอิง มันแม่นยำเพียงทศนิยมสามตำแหน่งเท่านั้น

ที่บันทึกไว้ 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

Python ขนาด 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

golfed

มันคำนวณ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

Perl 6 , 42 ไบต์

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

(การแปลตัวอย่างรหัส Matlab)

ทดสอบ:

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

ความจริง 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

Common Lisp, 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))

การใช้reduceกับ:from-end tเลี่ยงความจำเป็นในการทำแลมบ์ดากลาง "การย้อนกลับการยกกำลัง" (โดยทั่วไป(lambda (x y) (expt y x))ประหยัด 14 ไบต์ (12 ถ้าคุณลบช่องว่างแบบถอดออกได้)

เรายังคงต้องจัดการกับโฟลว์โอเวอร์โฟลว์ แต่ignore-errorsแบบฟอร์มส่งคืนnilหากเกิดข้อผิดพลาดดังนั้นเราจึงสามารถใช้orเพื่อระบุค่าเริ่มต้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.