计算阶乘的逆


30

编写最短的代码,该代码将接受大于1的任何实数作为输入,并输出其正反阶乘。换句话说,它回答“什么阶乘等于该数字?”的问题。使用伽玛功能作为描述阶乘扩展定义任意实数这里

例如:

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

因为3! = 63.390077654! = 10

规则

  • 禁止使用内置的阶乘函数或伽马函数,或依赖于这些函数的函数。
  • 该程序应该能够将其计算为5个十进制数字,并且具有理论上能够将其计算为任意精度的能力(它应该包含可以任意增大或减小以获取任意精度的数字)
  • 允许使用任何语言,以字符中最短的代码为准。

我在这里做了一个有效的例子。看一看。


2
这可能会使用更多的测试用例,尤其是要涵盖零和负输入。
彼得·泰勒

我编辑输入应该大于1,因为否则可能会有多个答案。
延斯(Jens Renders)2014年

1
可以有多个答案,无论如何,除非您还添加了一个要求,即输出必须大于1
彼得·泰勒

您的工作示例在输入24时给出3.99999。那么这样的解决方案可以接受吗?
rubik 2014年

是的,因为这可以看作是4到5个小数位正确
Jens Renders

Answers:


13

Java语言(116)

黑魔法在这里!在几毫秒内给出结果。
只有小学数学函数中使用:lnpowexponential

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上不受支持,但基本上,我为和编写了牛顿求解器(因为是),并对γ和digamma函数进行了近似。f(y)=gamma(y)-n=0x=y-1x!gamma(x+1)

伽玛近似是斯特林近似伽玛近似
使用欧拉·麦克劳林公式
伽玛函数是伽玛函数除以伽玛函数的导数: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 2014年

@JensRenders,好吧,我添加了牛顿求解器的一些迭代,更改了初始猜测,并更好地近似了伽玛函数。现在应该符合规则了。如果可以的话,让我现在:)
Michael M.

是的,它非常完美,我投了赞成票:)
Jens Renders 2014年

1
您可以保存1个字符:n=prompt(M=Math)
佛罗伦萨

尝试对$ 10 ^ {10 ^ 6} $之类的大量代码运行代码,并确保获得整数结果
David G. Stork 2015年

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 2014年

4
Mathematica对数学东西太不公平了!:D
Michael M.

1
从名字本身数学
达丹

是否NumberQ需要图案测试?或原谅E^(-t)?难道是欺骗转NIntegrateIntegrate?可能... :)
Orion 2014年

它正在变成一个真正的挑战;)
mmumboss 2014年

6

伊斯德: 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。


一年过期更新:

我只是意识到这是非常低效的。击打至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 2014年

@JensRenders:我刚刚做过;)
mmumboss 2014年

为了澄清有关精度的讨论:它由.1(积分步骤)和99(积分极限)设置。对分关系到机器精度。除非希望输入大于(99!)的数字,否则对分限制@ 1,99可以保持为99。
Orion 2014年

@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 2014年

我也没有在ised和Mathematica解决方案中看到它吗?不过,我会考虑它..
mmumboss

1
我看到的数字99在ISED版本,Mathematica的版本反正挨打
延呈现

给定代码中的位置,这可能是积分的上限。在我的代码中,这是inf。是的,如果我将inf更改为99,我的答案将变得不太准确,这意味着此数字会影响精度,因此我符合规则。如果将其更改为99,我什至还保存了一个字符;)
mmumboss 2014年

但是将inf更改为99后,是否满足所需的精度?
rubik 2014年

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)如果您将递归限制设置为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问题,因此您需要提供最短的答案,说明解决方案的长度。
2014年

一个很好的方法,但是问题是您无法保证这将永远找到答案……而且,这是codegolf zo,您可以尝试最小化字符使用。
Jens Renders 2014年

1
Python的random()使用Mersenne Twister,我相信它会绕过Python的浮点数,因此,如果在公差范围内有答案,它应始终终止。
intx13 2014年

您是说它在重复一个浮点值之前返回每个浮点值吗?如果真是这样,那么如果您能够克服堆栈溢出的问题,那么此代码将是有效的
Jens Renders

2
该代码具有功能,只是您和我可能没有时间或没有计算机资源来执行它;)
intx13 2014年

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;breakprint x以删除50个字符。它会永远循环,为您提供越来越准确的估计。虽然不确定这是否符合规则。


我不知道该网站计算字符数。我总是用cat file | wc -c
rubik 2014年

@rubik:哦,很好,没想到要使用它。他们都匹配=)
Claudiu 2014年

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字节码,因此这也应该适用于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 2014年

那很棒!我不知道上限在哪里,但是应该在某个地方打破。因为1e100它给出:69.957805200000011e150所以它输出96.10586423000002,而1e200它就爆炸了。但是我真的不知道这些结果是否可靠...
rubik 2014年

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)

在线尝试!

取消评论

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(不使用循环!)

为此,我使用了Stirling阶乘近似的逆数的众所周知的数值近似(也从这个..咳嗽..咳嗽... 别人的代码中得到了启发...)

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)))))))))
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.