คำนวณค่าผกผันของแฟคทอเรียล


30

เขียนรหัสที่สั้นที่สุดที่จะใช้จำนวนจริงใด ๆ ที่มากกว่า 1 เป็นอินพุตและจะส่งออกปัจจัยการผกผันในเชิงบวก มันจะตอบคำถามที่ว่า "เลขแฟคทอเรียลเท่ากับจำนวนนี้คืออะไร" ใช้ฟังก์ชันแกมมาเพื่อขยายคำนิยามสำหรับปัจจัยที่จะจำนวนจริงใด ๆ ตามที่อธิบายไว้ที่นี่

ตัวอย่างเช่น:

input=6 output=3 
input=10 output=3.390077654

เพราะ3! = 6และ3.390077654! = 10

กฎระเบียบ

  • ห้ามมิให้ใช้ฟังก์ชันแบบแฟคทอเรียลหรือฟังก์ชันแกมม่าหรือฟังก์ชันที่พึ่งพาฟังก์ชันเหล่านี้
  • โปรแกรมควรจะสามารถคำนวณให้เป็นทศนิยม 5 หลักด้วยความสามารถทางทฤษฎีในการคำนวณความแม่นยำใด ๆ (มันควรมีจำนวนที่สามารถทำให้ใหญ่หรือเล็กตามอำเภอใจเพื่อความแม่นยำโดยพลการ)
  • อนุญาตให้ใช้ภาษาใดก็ได้รหัสที่สั้นที่สุดจะเป็นตัวอักษรที่ชนะ

ฉันทำตัวอย่างการทำงานที่นี่ ได้ดู


2
กรณีนี้อาจใช้กรณีทดสอบเพิ่มอีกโดยเฉพาะอย่างยิ่งเพื่อให้ครอบคลุมศูนย์และอินพุตเชิงลบ
Peter Taylor

ฉันแก้ไขว่าอินพุตควรมากกว่า 1 เพราะมิฉะนั้นอาจมีคำตอบ muliple
Jens Renders

1
สามารถมีได้หลายคำตอบต่อไปเว้นแต่คุณจะเพิ่มข้อกำหนดที่ผลลัพธ์ต้องมากกว่า 1
Peter Taylor

ตัวอย่างการทำงานของคุณให้ 3.99999 เมื่อป้อน 24 ดังนั้นโซลูชันดังกล่าวจึงเป็นที่ยอมรับหรือไม่
rubik

ใช่เพราะสิ่งนี้สามารถมองเห็นได้เป็น 4, ถึง 5 ตำแหน่งทศนิยมที่ถูกต้อง
Jens Renders

คำตอบ:


13

Javascript (116)

มนต์ดำที่นี่! ให้ผลในไม่กี่มิลลิวินาที
เพียงฟังก์ชั่นที่ใช้คณิตศาสตร์ระดับประถมศึกษา: ln, pow,exponential

x=9;n=prompt(M=Math);for(i=1e4;i--;)x+=(n/M.exp(-x)/M.pow(x,x-.5)/2.5066/(1+1/12/x+1/288/x/x)-1)/M.log(x);alert(x-1)

LaTeX ที่แย่มากไม่รองรับ codegolf แต่โดยทั่วไปฉันเขียนตัวแก้นิวตันสำหรับf(y)=gamma(y)-n=0และx=y-1(เพราะx!เป็นgamma(x+1)) และการประมาณสำหรับฟังก์ชันแกมม่าและ Digamma

การประมาณแบบแกมม่าเป็นการประมาณแบบสเตอร์ลิงการประมาณแบบ
ดิจมาม่าใช้สูตรออยเลอร์แมคลูริน
ฟังก์ชันดิจิม่ามาเป็นอนุพันธ์ของฟังก์ชันแกมมาหารด้วยฟังก์ชันแกมม่า:f'(y)=gamma(y)*digamma(y)

Ungolfed:

n = parseInt(prompt());
x = 9; //first guess, whatever but not too high (<500 seems good)

//10000 iterations
for(i=0;i<10000;i++) {

  //approximation for digamma
  d=Math.log(x);

  //approximation for gamma
  g=Math.exp(-x)*Math.pow(x,x-0.5)*Math.sqrt(Math.PI*2)*(1+1/12/x+1/288/x/x);

  //uncomment if more precision is needed
  //d=Math.log(x)-1/2/x-1/12/x/x+120/x/x/x/x;
  //g=Math.exp(-x)*Math.pow(x,x-0.5)*Math.sqrt(Math.PI*2)*(1+1/12/x+1/288/x/x-139/51840/x/x/x);

  //classic newton, gamma derivative is gamma*digamma
  x-=(g-n)/(g*d);
}

alert(x-1);

กรณีทดสอบ:

10 => 3.390062988090518
120 => 4.99999939151027
720 => 6.00000187248195
40320 => 8.000003557030217
3628800 => 10.000003941731514

คำตอบที่ดีมากมันไม่ตรงกับความต้องการที่แม่นยำและใช้ได้กับตัวเลขที่น้อยกว่า 706
Jens Renders

@ JensRenders ดีฉันได้เพิ่มการวนซ้ำของตัวแก้นิวตันเปลี่ยนการคาดเดาเริ่มต้นและการประมาณที่ดีกว่าสำหรับฟังก์ชันแกมมา ที่ควรเหมาะกับกฎตอนนี้ ให้ฉันตอนนี้ถ้ามันไม่เป็นไร :)
Michael M.

ใช่ตอนนี้ก็สมบูรณ์แบบผมลงคะแนนมันขึ้น :)
Jens Renders

1
คุณสามารถบันทึก 1 ตัวอักษร:n=prompt(M=Math)
Florent

ลองใช้รหัสของคุณเป็นจำนวนมากเช่น $ 10 ^ {10 ^ 6} $ และให้แน่ใจว่าคุณได้รับผลจำนวนเต็ม
David G. Stork

13

Mathematica - 74 54 49

วิธีที่เหมาะสมจะเป็น

f[x_?NumberQ]:=NIntegrate[t^x E^-t,{t,0,∞}]
x/.FindRoot[f@x-Input[],{x,1}]

ถ้าเราเพียงวางทดสอบ?NumberQมันจะยังคงทำงาน แต่โยนบางคำเตือนที่น่ารังเกียจซึ่งจะหายไปถ้าเราเปลี่ยนไปบูรณาการเชิงสัญลักษณ์Integrateแต่นี้จะผิดกฎหมาย (ผมคิดว่า) เพราะฟังก์ชั่นจะถูกแปลงโดยอัตโนมัติGammaฟังก์ชั่น นอกจากนี้เราสามารถกำจัดฟังก์ชั่นภายนอกด้วยวิธีนี้

อย่างไรก็ตาม

x/.FindRoot[Integrate[t^x E^-t,{t,0,∞}]-Input[],{x,1}]

เพื่อให้ได้อินพุตที่เหมาะสมเพียงแค่นิยามฟังก์ชั่น (ไม่อนุญาตให้ MatLab ชนะ)

x/.FindRoot[Integrate[t^x E^-t,{t,0,∞}]-#,{x,1}]&

หากอนุญาตให้ใช้แฟคทอเรียลในตัว

N@InverseFunction[#!&]@Input[]

ข้างต้นไม่ได้ให้จำนวนเต็ม (ซึ่งเป็นอาร์กิวเมนต์สำหรับฟังก์ชั่นปัจจัยที่แท้จริง) ดังต่อไปนี้:

Floor[InverseFunction[Gamma][n]-1]

อ่าฟังก์ชั่นในตัวทั้งหมด! ฉันไม่คิดว่าจะเอาชนะได้ยกเว้นในทำนองเดียวกัน
rubik

4
Mathematica นั้นไม่ยุติธรรมสำหรับเรื่องคณิตศาสตร์! : D
Michael M.

1
จากชื่อของตัวเอง MATHematica
Dadan

มีการNumberQทดสอบรูปแบบต้อง? หรือ parens ในE^(-t)? มันโกงที่จะหันNIntegrateไปIntegrate? อาจเป็น ... :)
orion

มันกลายเป็นความท้าทายที่แท้จริง;)
mmumboss

6

ised: 72 46 ตัวอักษร

นี้เกือบจะเป็นแบบที่สมบูรณ์แบบ ... มี "ภาษา" ออกมีที่ดูเหมือนว่าจะมีความหมายอย่างแม่นยำสำหรับการเล่นกอล์ฟคณิตศาสตร์: ised ไวยากรณ์ที่ยุ่งเหยิงของมันทำให้โค้ดสั้นมาก (ไม่มีตัวแปรที่ระบุชื่อเพียงแค่สล็อตหน่วยความจำจำนวนเต็มและตัวดำเนินการถ่านหลายตัว) การกำหนดฟังก์ชั่นแกมม่าโดยใช้อินทิกรัลฉันทำได้ถึง 80 ตัวอักษรที่ดูเหมือนสุ่ม

@4{:.1*@+{@3[.,.1,99]^x:*exp-$3}:}@6{:@{$4::@5avg${0,1}>$2}$5:}@0,0@1,99;$6:::.

ในที่นี้สล็อตหน่วยความจำ $ 4 เป็นฟังก์ชั่นแฟกทอเรียลสล็อตหน่วยความจำ $ 6 ฟังก์ชั่นการแบ่งส่วนและสล็อตหน่วยความจำ $ 2 คาดว่าจะถูกตั้งค่าให้ป้อนข้อมูล สล็อต $ 0 และ $ 1 เป็นขอบเขตแบ่งออกเป็นสองส่วน ตัวอย่างการโทร (สมมติว่ามีโค้ดข้างต้นอยู่ในไฟล์inversefactorial.ised)

bash> ised '@2{556}' --f inversefactorial.ised
556
5.86118

แน่นอนคุณสามารถใช้ builtin! โอเปอเรเตอร์ซึ่งในกรณีนี้คุณจะได้รับไม่เกิน 45 อักขระ

@6{:@{{@5avg${0,1}}!>$2}$5:}@0,0@1,99;$6:::.

ระวังการกระทำของผู้ประกอบการบางครั้งก็แปลก

แก้ไข: จำได้ว่าต้องอินไลน์ฟังก์ชั่นแทนการบันทึก เอาชนะ Mathematica ด้วยตัวละคร 72 ตัว!

@0,0@1,99;{:@{{:.1*@+{@3[.,.1,99]^x:*exp-$3}:}::@5avg${0,1}>$2}$5:}:::.

และใช้! ในตัวคุณได้รับ 41


การอัปเดตเกินเวลาหนึ่งปี:

ฉันเพิ่งรู้ว่านี่ไม่มีประสิทธิภาพสูง Golfed-down ถึง 60 ตัวอักษร:

@0#@1,99;{:@{.1*@3[.,.1,99]^@5avg${0,1}@:exp-$3>$2}$5:}:::.

ถ้าใช้ utf-8 (Mathematica ก็ทำเช่นกัน) เราจะได้ 57:

@0#@1,99;{:@{.1*@3[.,.1,99]^@5avg${0,1}·exp-$3>$2}$5:}∙.

การเขียนที่แตกต่างกันเล็กน้อยสามารถลดได้ถึง 46 (หรือ 27 หากใช้ builtin!):

{:x_S{.5@3[.,.1,99]^avgx·exp-$3*.1<$2}:}∙∓99_0

สามารถลบอักขระสองตัวสุดท้ายได้หากคุณตกลงที่จะพิมพ์คำตอบสองครั้ง


ฉันจะประหลาดใจถ้าฉันเห็นใครบางคนเอาชนะสิ่งนี้: o
Jens Renders

@ JensRenders: ฉันเพิ่งทำ;)
mmumboss

เพื่อชี้แจงการอภิปรายเกี่ยวกับความแม่นยำ: กำหนดโดย. 1 (ขั้นตอนการรวม) และ 99 (ขีด จำกัด การรวม) การแบ่งส่วนจะไปที่ความแม่นยำของเครื่อง ขีด จำกัด bisection @ 1,99 สามารถเก็บไว้ที่ 99 ยกเว้นว่าคุณต้องการป้อนหมายเลขด้านบน (99!)
orion

@mmumboss มีคุณอีกครั้ง :)
Orion

5

MATLAB 54 47

ถ้าฉันเลือกความท้าทายที่ถูกต้อง MATLAB นั้นดีมากสำหรับการเล่นกอล์ฟ :) ในรหัสของฉันฉันพบวิธีแก้สมการ (ux!) = 0 ซึ่งคุณเป็นผู้ใช้และ x ตัวแปรที่จะแก้ไข ซึ่งหมายความว่า u = 6 จะนำไปสู่ ​​x = 3 ฯลฯ ...

@(x)fsolve(@(y)u-quad(@(x)x.^y./exp(x),0,99),1)

ความถูกต้องสามารถเปลี่ยนแปลงได้โดยการแก้ไขขีด จำกัด บนของอินทิกรัลซึ่งตั้งไว้ที่ 99 การลดค่านี้จะเปลี่ยนความแม่นยำของเอาต์พุตดังนี้ ตัวอย่างเช่นอินพุต 10:

upper limit = 99; answer = 3.390077650833145;
upper limit = 20; answer = 3.390082293675363;
upper limit = 10; answer = 3.402035336604546;
upper limit = 05; answer = 3.747303578099607;

เป็นต้น


คุณควรระบุตัวเลือกเพื่อความถูกต้องตามที่กำหนดไว้ในกฎ! "ควรมีตัวเลขที่สามารถทำให้ใหญ่หรือเล็กตามอำเภอใจเพื่อความแม่นยำตามอำเภอใจ"
Jens Renders

ฉันไม่เห็นในโซลูชัน ised และ Mathematica ใช่ไหม แต่ฉันจะดูมัน ..
mmumboss

1
ฉันเห็นหมายเลข 99 ในเวอร์ชัน ised และเวอร์ชัน mathematica นั้นถูกเอาชนะไปแล้ว
Jens Renders

รับตำแหน่งในรหัสนี่อาจเป็นขีด จำกัด บนของอินทิกรัล ในรหัสของฉันนี่คือ inf ดังนั้นถ้าฉันเปลี่ยน inf นี้เป็น 99 คำตอบของฉันจะแม่นยำน้อยกว่าซึ่งหมายความว่าจำนวนนี้มีผลต่อความแม่นยำและดังนั้นฉันจึงปฏิบัติตามกฎ ถ้าฉันเปลี่ยนเป็น 99 ฉันยังประหยัดถ่าน;)
mmumboss

แต่หลังจากเปลี่ยน inf เป็น 99 แล้วมันตอบสนองความต้องการที่แม่นยำหรือไม่?
rubik

3

Python - 199 ตัวอักษร

ตกลงดังนั้นคุณจะต้องใช้พื้นที่สแต็คและเวลามาก แต่เดี๋ยวก่อนมันจะไปถึงที่นั่น!

from random import *
from math import e
def f(x,n):
    q=randint(0,x)+random()
    z=0
    d=0.1**n
    y=d
    while y<100:
            z+=y**q*e**(-y)*d
            y+=d
    return q if round(z,n)==x else f(x,n)

นี่คือวิธีการอื่นที่มีการเรียกซ้ำมากกว่าเดิม

from random import *
from math import e
def f(x,n):
    q=randint(0,x)+random()
    return q if round(h(q,0,0.1**n,0),n)==x else f(x,n)
def h(q,z,d,y):
    if y>100:return z
    else:return h(q,z+y**q*e**(-y)*d,d,y+d)

คุณสามารถทดสอบทั้งสองอย่างนี้ได้>>>f(10,1)หากคุณตั้งค่าขีด จำกัด การเรียกซ้ำประมาณ 10,000 ตำแหน่งความแม่นยำทศนิยมมากกว่าหนึ่งตำแหน่งอาจไม่สมบูรณ์ด้วยข้อ จำกัด การเรียกซ้ำที่เหมือนจริง

การรวมความคิดเห็นและการแก้ไขเล็กน้อยลงไปที่ 199 ตัว

from random import*
from math import*
def f(x,n):
    q=random()*x+random()
    z=y=0
    while y<100:
            z+=y**q*e**-y*0.1**n
            y+=0.1**n
    return q if round(z,n)==x else f(x,n)

2
นี่คือcode-golfคำถามดังนั้นคุณจำเป็นต้องให้คำตอบที่สั้นที่สุดโดยระบุความยาวของโซลูชันของคุณ
VisioN

วิธีการที่ดี แต่ปัญหาคือคุณไม่สามารถรับประกันได้ว่านี่จะพบคำตอบ ... นอกจากนี้นี่คือ codegolf zo คุณอาจพยายามลดการใช้อักขระให้น้อยที่สุด
Jens Renders

1
Python Random () ใช้ Mersenne Twister ซึ่งฉันเชื่อว่าการเดินไปในอวกาศของ Python Floats ดังนั้นมันควรจะยุติหากมีคำตอบอยู่ในความอดทน
intx13

คุณหมายถึงว่ามันจะส่งกลับทุกค่าลอยก่อนทำซ้ำหรือไม่ หากเป็นกรณีที่เกินรหัสนี้จะถูกต้องหากคุณสามารถเอาชนะสแต็คล้นได้
Jens Renders

2
รหัสมีความสามารถก็แค่คุณและฉันอาจไม่ได้มีเวลาหรือทรัพยากรคอมพิวเตอร์ที่จะดำเนินการให้เสร็จ;)
intx13

3

Python 2.7 - 215 189 ตัวอักษร

f=lambda t:sum((x*.1)**t*2.71828**-(x*.1)*.1for x in range(999))
n=float(raw_input());x=1.;F=0;C=99
while 1:
 if abs(n-f(x))<1e-5:print x;break
 F,C,x=f(x)<n and(x,C,(x+C)/2)or(F,x,(x+F)/2)

การใช้งาน:

# echo 6 | python invfact_golf.py
2.99999904633
# echo 10 | python invfact_golf.py
3.39007514715
# echo 3628800 | python invfact_golf.py
9.99999685376

หากต้องการเปลี่ยนความแม่นยำ: เปลี่ยน1e-5เป็นจำนวนที่น้อยลงเพื่อความแม่นยำที่มากขึ้นจำนวนที่มากขึ้นสำหรับความแม่นยำที่แย่ลง eเพื่อความแม่นยำที่ดีกว่าคุณอาจต้องการที่จะให้ค่าที่ดีสำหรับ

นี่ใช้ฟังก์ชันแฟคทอเรียลเป็นfแล้วทำการค้นหาแบบไบนารีเพื่อค้นหาค่าที่ถูกต้องที่สุดของค่าอินเวอร์สของอินพุต สมมติว่าคำตอบนั้นน้อยกว่าหรือเท่ากับ 99 (มันจะไม่ทำงานสำหรับคำตอบ 365 แน่นอนฉันได้รับข้อผิดพลาดทางคณิตศาสตร์ล้น) การใช้พื้นที่และเวลาอย่างสมเหตุสมผลจะสิ้นสุดลงเสมอ

อีกวิธีหนึ่งคือแทนที่if abs(n-f(x))<=10**-5: print x;breakด้วยprint xการโกนออก50 ตัวอักษร มันจะวนซ้ำตลอดไปทำให้คุณประมาณการถูกต้องมากขึ้น ไม่แน่ใจว่าสิ่งนี้จะสอดคล้องกับกฎว่า


ฉันไม่รู้ว่าไซต์จะนับตัวอักษร cat file | wc -cฉันมักจะใช้
rubik

@rubik: โอ้ดีไม่คิดว่าจะใช้ พวกเขาทั้งคู่ =)
Claudiu

2

dg - 131 133 ไบต์

o,d,n=0,0.1,float$input!
for w in(-2..9)=>while(sum$map(i->d*(i*d)**(o+ 10**(-w))/(2.718281**(i*d)))(0..999))<n=>o+=10**(-w)
print o

เนื่องจาก dg สร้าง CPC bytecode สิ่งนี้ควรนับสำหรับ Python ด้วย แต่โอ้ ... ตัวอย่างบางส่วน:

$ dg gam.dg 
10
3.3900766499999984
$ dg gam.dg 
24
3.9999989799999995
$ dg gam.dg 
100
4.892517629999997
$ dg gam.dg 
12637326743
13.27087070999999
$ dg gam.dg  # i'm not really sure about this one :P it's instantaneous though
28492739842739428347929842398472934929234239432948923
42.800660880000066
$ dg gam.dg  # a float example
284253.232359
8.891269689999989

แก้ไข: เพิ่มสองไบต์เพราะฉันจำไม่ได้ว่าควรยอมรับการลอยเช่นกัน!


เหมืองให้42.8006566063ดังนั้นพวกเขาจึงจับคู่กับความแม่นยำภายใน 5 หลัก!
Claudiu

เยี่ยมมาก! ฉันไม่รู้ว่าขอบเขตด้านบนอยู่ที่ใด สำหรับ1e100มันจะช่วยให้: 69.95780520000001สำหรับ1e150มันจะออกผลลัพธ์96.10586423000002ในขณะที่สำหรับ1e200มันแรงขึ้น แต่จริง ๆ แล้วฉันไม่รู้ว่าผลลัพธ์เหล่านั้นเชื่อถือได้หรือไม่ ...
rubik

1

R , 92 ไบต์

ฟังก์ชั่นgซึ่งใช้อินzพุทและเอาท์พุทแฟคทอเรียลของจำนวนนั้น

มีสนามกอล์ฟเกือบจะแน่นอนกว่านี้ดังนั้นหากคุณเห็นสิ่งที่ฉันสามารถปรับปรุงได้โปรดแจ้งให้เราทราบ

library(pryr)
g=f(z,uniroot(f(a,integrate(f(x,x^a*exp(-x)),0,Inf)$v-z),c(0,z+1),tol=1e-9)$r)

ลองออนไลน์!

Ungolfed และแสดงความคิดเห็น

library(pryr)                     # Add pryr to workspace
inv.factorial = f(z,              # Declare function which  
  uniroot(                        # Finds the root of
    f(a, integrate(               # The integral of 
      f(x, x^a*exp(-x))           # The gamma function
        ,0 ,Inf                   # From 0 to Infinity
      )$value-z                   # Minus the input value, `z`
    ), c(0, z+1),                 # On the bound of 0 to z+1
    tol = 1e-323                  # With a specified tolerance
  )$root                          # And outputs the root
)                                 # End function

ลองออนไลน์!


0

Javascript (โดยไม่ใช้ลูป!)

เมื่อต้องการทำสิ่งนี้ฉันใช้การประมาณเชิงตัวเลขที่รู้จักกันดีของการผกผันของการประมาณค่าสเตอร์ลิง (และยังได้รับแรงบันดาลใจจาก .. ไอ .. รหัสของคนอื่น ... )

function f(n){
    if(n==1) return 1;
    else if(n==2) return 2;
    else if(n==6) return 3;
    else if(n==24) return 4;
    else{
        return Math.round((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))/Math.log((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))))/Math.log((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))/Math.log((((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592))+(Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))/Math.log((Math.log(n)/Math.LN10 *  Math.log(10.) - .5 * Math.log(2.*3.141592)))))))))
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.