계승의 역수를 계산


30

1보다 큰 실수를 입력으로 사용하고 양의 역 인수를 출력하는 가장 짧은 코드를 작성하십시오. 즉, "이 숫자와 어떤 계승이 같은가?"라는 질문에 대답합니다. 여기에 설명 된대로 감마 함수를 사용하여 계승 정의를 실수로 확장합니다 .

예를 들면 다음과 같습니다.

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

때문에 3! = 63.390077654! = 10

규칙

  • 내장 계승 함수 또는 감마 함수 또는 이러한 함수에 의존하는 함수를 사용하는 것은 금지되어 있습니다.
  • 프로그램은 소수점 이하 5 자리까지 계산할 수 있어야하며 이론상 모든 정밀도로 계산할 수 있어야합니다 (임의의 정밀도를 얻기 위해 임의의 크거나 작은 숫자를 포함해야 함)
  • 모든 언어가 허용되며 문자가 가장 짧은 코드가 승리합니다.

나는 여기에 실례를 만들었다 . 보세요


2
이것은 특히 제로 및 네거티브 입력을 다루기 위해 더 많은 테스트 사례를 사용할 수 있습니다.
피터 테일러

다른 답변이있을 수 있기 때문에 입력이 1보다 커야한다고 편집했습니다.
Jens Renders

1
출력이 1보다 커야한다는 요구 사항을 추가하지 않으면 여러 대답이있을 수 있습니다.
Peter Taylor

당신의 작업 예제는 24를 입력했을 때 3.99999를줍니다.
rubik

네, 소수점 이하 4 자리에서 5 자리까지 올바를 수 있습니다.
Jens Renders

답변:


13

자바 스크립트 (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)

너무 나쁜 라텍스 codegolf에서 지원되지 않지만, 기본적으로, 나는 코딩 뉴턴 솔버를 위한 f(y)=gamma(y)-n=0x=y-1(때문 x!이다 gamma(x+1))와 근사 감마 및 digamma 기능.

감마 근사값은 스털링 근사값입니다. 감마 근사값
사용 오일러 맥라 우린 공식
감마 함수는 감마 함수를 감마 함수로 나눈 값입니다.f'(y)=gamma(y)*digamma(y)

언 골프 :

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

수학- 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패턴 테스트가 필요합니다? 아니면 파 렌스 E^(-t)? 그것은 설정하는 속임수 NIntegrateIntegrate? 아마 ... :)
오리온

그것은 진짜 도전으로
바뀌고 있습니다

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

물론 내장을 사용할 수 있습니다! 연산자 (이 경우 45 자 이하)

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

신중하고 운영자 우월성은 때때로 이상합니다.

편집 : 함수를 저장하는 대신 인라인해야합니다. 72 자로 Mathematica를 이길 수 있습니다!

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

그리고! 내장하면 41이됩니다.


1 년 기한이 지난 업데이트 :

방금 이것이 매우 비효율적이라는 것을 깨달았습니다. 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).

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

답을 두 번 인쇄해도 괜찮 으면 마지막 두 문자를 제거 할 수 있습니다.


누군가 이걸 이길 수 있다면 놀라게 될 것입니다 : o
Jens Renders

@JensRenders : 방금했다;)
mmumboss

정확도에 대한 논의를 명확하게하기 위해 : .1 (통합 단계) 및 99 (통합 한계)로 설정됩니다. 이분법은 기계 정밀도로갑니다. (99!) 이상의 숫자를 입력하지 않으면이 분할 한계 @ 1,99를 99로 유지할 수 있습니다.
오리온

@mmumboss는 다시 당신을 얻었다 :)
orion

5

MATLAB 54 47

내가 올바른 도전을 선택하면 MATLAB은 골프에 정말 좋습니다 :). 내 코드에서 나는 방정식 (ux!) = 0에 대한 해결책을 찾았습니다. 여기서 u는 사용자 입력이고 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
나는 ised 버전에서 99 번을 보았고 mathematica 버전은 어쨌든 이겼습니다
Jens Renders

코드에서 위치가 주어지면 이것은 적분의 상한 일 것입니다. 내 코드에서 이것은 inf입니다. 예,이 inf를 99로 변경하면 내 대답의 정확성이 떨어집니다.이 숫자는 정밀도에 영향을 미치므로 규칙을 준수합니다. 99로 변경하면 문자도 저장합니다.)
mmumboss

그러나 inf를 99로 변경하면 필요한 정밀도를 충족합니까?
rubik

3

파이썬-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)재귀 한계를 약 10000으로 설정 한 경우이 두 가지를 모두 테스트 할 수 있습니다. 소수점 이하 두 자리 이상의 정확도는 실제 재귀 한계로 완료되지 않을 수 있습니다.

주석과 몇 가지 수정 사항을 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를 사용합니다 .Mersenne Twister는 Python 수레의 공간을 걷는다고 생각하므로 허용 오차 내에 답변이 있으면 항상 종료해야합니다.
intx13

반복하기 전에 모든 float 값을 반환한다는 의미입니까? 만약 스택 오버 플로우를 극복 할 수 있다면이 코드보다 유효하다면
Jens Renders

2
코드는 가능하다. 단지 당신과 나는 그것을 완료 할 시간이나 컴퓨터 자원이 없을지도 모른다;)
intx13

3

파이썬 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하여 50자를print x 깎으십시오 . 영원히 반복되므로 더 정확한 견적을 얻을 수 있습니다. 이것이 규칙에 맞는지 확실하지 않습니다.


나는 문자를 세는 사이트를 몰랐다. 나는 항상 사용 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는 CPython 바이트 코드를 생성하기 때문에 파이썬에도 포함되어야하지만 아 ... 몇 가지 예 :

$ 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

편집 : float도 받아 들여야한다는 것을 기억하지 못했기 때문에 2 바이트가 추가되었습니다!


광산은을 제공 42.8006566063하므로 5 자리의 정밀도로 일치합니다!
Claudiu

대단해! 나는 상한이 어디에 있는지 모르지만 어딘가에서 깨져야합니다. 내용 1e100이 제공 : 69.95780520000001위해 1e150그 출력 96.10586423000002을위한 반면 1e200는 불면. 그러나 실제로 나는 그 결과가 신뢰할
만한지

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

자바 스크립트 (루프를 사용하지 않고!)

이렇게하려면, 내가 잘 알려진 사용 스털링 계승 근사의 역의 수치 근사 (그리고이 ..cough .. 기침에 의해 영감을 얻었다 .. 다른 사람의 코드를 ...)

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.