Tính toán nghịch đảo của giai thừa


30

Viết mã ngắn nhất sẽ lấy bất kỳ số thực nào lớn hơn 1 làm đầu vào và sẽ đưa ra giai đoạn nghịch đảo dương của nó. Nói cách khác, nó trả lời câu hỏi "số nhân nào bằng số này?". Sử dụng hàm Gamma để mở rộng định nghĩa cho giai thừa cho bất kỳ số thực nào như được mô tả ở đây .

Ví dụ:

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

bởi vì 3! = 63.390077654! = 10

Quy tắc

  • Nghiêm cấm sử dụng các chức năng giai thừa hoặc chức năng gamma được xây dựng hoặc các chức năng dựa trên các chức năng này.
  • Chương trình có thể tính toán thành 5 chữ số thập phân, với khả năng lý thuyết để tính toán nó với bất kỳ độ chính xác nào (Nó nên chứa một số có thể được thực hiện lớn hay nhỏ để có độ chính xác tùy ý)
  • Bất kỳ ngôn ngữ nào đều được phép, mã ngắn nhất trong các ký tự sẽ thắng.

Tôi đã làm một ví dụ làm việc ở đây . Có một cái nhìn.


2
Điều này có thể sử dụng một số trường hợp thử nghiệm hơn, đặc biệt là để bao gồm đầu vào không và âm.
Peter Taylor

Tôi đã chỉnh sửa rằng đầu vào phải lớn hơn 1 vì nếu không, có thể có câu trả lời trung gian.
Jens Render

1
Dù sao cũng có thể có nhiều câu trả lời trừ khi bạn cũng thêm một yêu cầu rằng đầu ra phải lớn hơn 1.
Peter Taylor

Ví dụ làm việc của bạn cho 3,99999 khi nhập 24. Vậy giải pháp như vậy có được chấp nhận không?
rubik

có bởi vì điều này có thể được xem là 4, đến 5 chữ số thập phân chính xác
Jens Render

Câu trả lời:


13

Javascript (116)

Ma thuật đen đây! Cho kết quả sau vài mili giây .
Chỉ hàm toán học tiểu học sử dụng: 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)

Quá tệ LaTeX không được hỗ trợ trên codegolf nhưng về cơ bản, tôi đã mã hóa một bộ giải newton cho f(y)=gamma(y)-n=0x=y-1(vì x!gamma(x+1)) và các xấp xỉ cho các hàm gamma và digamma.

Xấp xỉ gamma là xấp xỉ Stirling xấp xỉ
Digamma sử dụng công thức Euler Maclaurin
Hàm digamma là đạo hàm của hàm gamma chia cho hàm gamma:f'(y)=gamma(y)*digamma(y)

Ung dung:

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

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

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

Câu trả lời rất hay, nó không đáp ứng được độ chính xác cần thiết và nó chỉ hoạt động với các số nhỏ hơn 706
Jens Render

@JensRender, tốt, tôi đã thêm một số lần lặp của bộ giải newton, đã thay đổi dự đoán ban đầu và xấp xỉ tốt hơn cho chức năng gamma. Điều đó nên phù hợp với các quy tắc bây giờ. Hãy để tôi ngay bây giờ nếu nó ổn :)
Michael M.

Vâng, bây giờ nó hoàn hảo, tôi đã bình chọn nó :)
Jens Render

1
Bạn có thể tiết kiệm 1 char:n=prompt(M=Math)
Florent

Hãy thử chạy mã của bạn trên một số lượng lớn, chẳng hạn như $ 10 ^ {10 ^ 6} $ và đảm bảo rằng bạn nhận được kết quả số nguyên
David G. Stork

13

Toán học - 74 54 49

Cách thích hợp sẽ là

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

Nếu chúng ta bỏ bài kiểm tra ?NumberQthì nó vẫn hoạt động, nhưng đưa ra một số cảnh báo khó chịu, sẽ biến mất nếu chúng ta chuyển sang tích hợp biểu tượng Integrate, nhưng điều này sẽ là bất hợp pháp (tôi cho rằng), vì chức năng sẽ tự động được chuyển đổi thành Gammachức năng. Ngoài ra chúng ta có thể thoát khỏi chức năng bên ngoài theo cách đó.

Dù sao

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

Để tìm hiểu với đầu vào thích hợp, chỉ cần định nghĩa hàm (không thể để MatLab giành chiến thắng)

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

Nếu giai thừa tích hợp được cho phép

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

Ở trên không đưa ra một số nguyên (đó là đối số cho hàm giai thừa thực). Sau đây không:

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

Ahh tất cả các chức năng tích hợp! Tôi không nghĩ rằng điều này có thể đánh bại được ngoại trừ theo cách tương tự.
rubik

4
Mathematica là không công bằng cho các công cụ toán học! : D
Michael M.

1
từ chính cái tên MATHIALa
Dadan

NumberQthử nghiệm mẫu cần thiết? Hoặc parens trong E^(-t)? Là gian lận để chuyển NIntegratesang Integrate? Có lẽ ... :)
orion

Nó đang biến thành một thách thức thực sự;)
mmumboss

6

là: 72 46 ký tự

Điều này gần như là một sự phù hợp hoàn hảo ... có một "ngôn ngữ" ngoài kia dường như có nghĩa chính xác cho môn toán golf: ised . Cú pháp bị xáo trộn của nó tạo ra một mã rất ngắn (không có biến được đặt tên, chỉ có các khe nhớ số nguyên và rất nhiều toán tử char đơn đa năng). Xác định hàm gamma bằng tích phân, tôi nhận được tới 80 ký tự dường như ngẫu nhiên

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

Ở đây, khe cắm bộ nhớ $ 4 là một chức năng giai thừa, khe cắm bộ nhớ $ 6 chức năng chia đôi và khe cắm bộ nhớ $ 2 dự kiến ​​sẽ được đặt thành đầu vào (được đưa ra trước khi tìm mã nguồn này). Slots $ 0 và $ 1 là ranh giới chia đôi. Ví dụ cuộc gọi (giả sử mã ở trên có trong tệp inversefactorial.ised)

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

Tất nhiên, bạn có thể sử dụng nội dung! Toán tử, trong trường hợp đó bạn nhận được tối đa 45 ký tự

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

Cẩn thận, ưu tiên điều hành đôi khi là lạ.

Chỉnh sửa: ghi nhớ để nội tuyến các chức năng thay vì lưu chúng. Đánh bại Mathicala với 72 ký tự!

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

Và sử dụng! dựng sẵn bạn nhận được 41.


Cập nhật quá hạn một năm:

Tôi chỉ nhận ra điều này là không hiệu quả cao. Được giảm xuống còn 60 ký tự:

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

Nếu utf-8 được sử dụng (Mathicala cũng vậy), chúng tôi nhận được tới 57:

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

Viết lại một chút khác nhau có thể cắt nó xuống 46 (hoặc 27 nếu sử dụng nội dung!):

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

Hai ký tự cuối cùng có thể được loại bỏ nếu bạn ổn với câu trả lời được in hai lần.


Tôi sẽ ngạc nhiên nếu tôi thấy ai đó đánh bại điều này: o
Jens Render

@JensRender: Tôi vừa làm;)
mmumboss

Để làm rõ cuộc thảo luận về độ chính xác: nó được đặt bởi .1 (bước tích hợp) và 99 (giới hạn tích hợp). Sai số đi đến độ chính xác của máy. Giới hạn chia đôi @ 1,99 có thể được giữ ở mức 99 trừ khi bạn muốn nhập số ở trên (99!).
orion

@mmumboss có bạn một lần nữa :)
orion

5

MATLAB 54 47

Nếu tôi chọn đúng thử thách, MATLAB thực sự tốt cho việc chơi gôn :). Trong mã của tôi, tôi tìm giải pháp cho phương trình (ux!) = 0 trong đó u là đầu vào của người dùng và x biến để giải. Điều này có nghĩa là u = 6 sẽ dẫn đến x = 3, v.v ...

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

Độ chính xác có thể được thay đổi bằng cách thay đổi giới hạn trên của tích phân, được đặt ở mức 99. Việc hạ thấp này sẽ thay đổi độ chính xác của đầu ra như sau. Ví dụ: đầu vào là 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;

v.v.


bạn nên xác định tùy chọn cho chính xác vì điều này là bắt buộc trong các quy tắc! "Nó nên chứa một số có thể được tạo thành tùy ý lớn hay nhỏ để có được độ chính xác tùy ý"
Jens Render

Tôi cũng không thấy nó trong các giải pháp ised và Mathematica? Nhưng tôi sẽ xem xét nó ..
mmumboss

1
Tôi thấy số 99 trong phiên bản ised và phiên bản mathicala bị đánh bại dù sao đi nữa
Jens Render

Với vị trí trong mã, đây có lẽ là giới hạn trên cho tích phân. Trong mã của tôi đây là inf. Vì vậy, vâng, nếu tôi thay đổi inf này thành 99, câu trả lời của tôi trở nên kém chính xác hơn, điều đó có nghĩa là con số này ảnh hưởng đến độ chính xác, và do đó tôi đáp ứng các quy tắc. Nếu tôi đổi nó thành 99, tôi thậm chí còn lưu một ký tự;)
mmumboss

Nhưng sau khi thay đổi inf thành 99, nó có đáp ứng độ chính xác cần thiết không?
rubik

3

Python - 199 ký tự

Ok, vì vậy bạn sẽ cần rất nhiều không gian ngăn xếp và rất nhiều thời gian, nhưng này, nó sẽ đến đó!

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)

Đây là một cách tiếp cận khác với đệ quy nhiều hơ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)

Cả hai điều này đều có thể được kiểm tra với >>>f(10,1)điều kiện bạn đặt giới hạn đệ quy khoảng 10000. Nhiều hơn một vị trí chính xác thập phân có thể sẽ không hoàn thành với bất kỳ giới hạn đệ quy thực tế nào.

Kết hợp các ý kiến ​​và một vài sửa đổi, xuống tới 199 ký tự.

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
Đây là một code-golfcâu hỏi, vì vậy bạn cần cung cấp câu trả lời ngắn nhất, nêu rõ độ dài của giải pháp của bạn.
VisioN

Một phương pháp hay nhưng vấn đề là bạn không thể đảm bảo rằng điều này sẽ tìm thấy câu trả lời ... Ngoài ra, đây là codegolf zo mà bạn có thể cố gắng tối thiểu hóa việc sử dụng ký tự.
Jens Riders

1
Python 'Random () sử dụng Mersenne Twister mà tôi tin rằng không gian của phao của Python, vì vậy nó sẽ luôn chấm dứt nếu có câu trả lời trong phạm vi dung sai.
intx13

Bạn có nghĩa là nó trả về mọi giá trị float trước khi lặp lại một giá trị? nếu đó là trường hợp hơn mã này sẽ hợp lệ nếu bạn có thể khắc phục lỗi tràn ngăn xếp
Jens Render

2
Mã có khả năng, chỉ là bạn và tôi có thể không có thời gian cũng như tài nguyên máy tính để thực thi nó để hoàn thành;)
intx13

3

Python 2.7 - 215 189 ký tự

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)

Sử dụng:

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

Để thay đổi độ chính xác: thay đổi 1e-5thành số nhỏ hơn để có độ chính xác cao hơn, số lớn hơn cho độ chính xác kém hơn. Để có độ chính xác tốt hơn, bạn có thể muốn cung cấp một giá trị tốt hơn cho e.

Điều này chỉ thực hiện chức năng giai thừa như f, và sau đó thực hiện tìm kiếm nhị phân để tìm giá trị chính xác nhất của nghịch đảo của đầu vào. Giả sử câu trả lời nhỏ hơn hoặc bằng 99 (chắc chắn nó không hoạt động đối với câu trả lời là 365, tôi nhận được lỗi tràn toán học). Không gian rất hợp lý và thời gian sử dụng, luôn chấm dứt.

Ngoài ra, thay thế if abs(n-f(x))<=10**-5: print x;breakbằng print xđể cạo 50 ký tự . Nó sẽ lặp đi lặp lại mãi mãi, cho bạn ước tính chính xác hơn. Không chắc chắn nếu điều này sẽ phù hợp với các quy tắc mặc dù.


Tôi không biết trang web đó để đếm số ký tự. Tôi luôn luôn sử dụng cat file | wc -c.
rubik

@rubik: oh thật tuyệt, không nghĩ sẽ sử dụng nó. cả hai đều khớp nhau =)
Claudiu

2

dg - 131 133 byte

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

Vì dg tạo ra mã byte CPython nên nó cũng được tính cho Python, nhưng ồ ... Một số ví dụ:

$ 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

EDIT: Đã thêm hai byte vì tôi không nhớ rằng nó cũng nên chấp nhận float!


Của tôi cho 42.8006566063, vì vậy họ phù hợp trong vòng 5 chữ số chính xác!
Claudiu

Thật tuyệt! Tôi không biết giới hạn trên nằm ở đâu, nhưng nó sẽ bị phá vỡ ở đâu đó. Đối với 1e100nó cho : 69.95780520000001, cho 1e150nó đầu ra 96.10586423000002, trong khi cho 1e200nó nổ tung. Nhưng thực sự tôi không biết liệu những kết quả đó có đáng tin hay không ...
rubik

1

R , 92 byte

Một hàm, glấy đầu vào zvà xuất ra yếu tố nghịch đảo của số đó

Gần như chắc chắn sẽ có nhiều hơn để chơi golf về điều này, vì vậy nếu bạn thấy điều gì đó mà tôi có thể cải thiện, xin vui lòng cho tôi biết.

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)

Hãy thử trực tuyến!

Ungolfed và bình luận

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

Hãy thử trực tuyến!


0

Javascript (không sử dụng vòng lặp!)

Để làm điều này, tôi đã sử dụng một phép tính gần đúng số nổi tiếng về nghịch đảo của phép tính xấp xỉ Stirling Factorial , (và cũng lấy cảm hứng từ điều này ..cough .. ho .. mã của người khác ...)

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)))))))))
    }
}
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.