反Pi功能


17

Pi函数是阶乘实数(甚至复数)的扩展。对于整数nΠ(n)= n!,但是要获得关于实数的定义,我们使用积分来定义它:

Pi(z)=从0到无穷大的积分t e ^ -tt ^ z dt

在这个挑战中,我们将反转Π函数。

给定实数z≥1,找到正x使得Π(x)= z。您的答案必须是至少5位小数的准确数字。


例子:

120 -> 5.0000
10 -> 3.39008
3.14 -> 2.44815
2017 -> 6.53847
1.5 -> 1.66277

4
请注意,人们更多地使用Gamma(Γ)功能。((x)=Γ(x + 1)。但是IMOΓ是可憎的移位,Π是阶乘的真正扩展。
Orlp

1
Wellp,那系列的扩张足以吓我一跳... i.imgur.com/ttgzDSJ.gif
魔术八爪鱼

1
您提供的所有示例还具有其他解决方案,例如120 -> -0.991706。这是因为Π(x)随x从右到-1变为无穷大。也许您是要坚持x> 0。
格雷格·马丁

@GregMartin也已添加。
orlp

1
尽管看起来是不自然的,但出于某些原因,还是更倾向于使用转换版本。参见例如MathOverflow上的此答案以及该页面上的其他答案
Ruslan

Answers:


8

Mathematica,17 15 27字节

FindInstance[#==x!&&x>0,x]&

输出看起来像{{x -> n}}n解决方案在哪里,这可能是不允许的。


7

Pyth,4个字节

.I.!

接受数字输入并打印结果的程序。

测试套件

怎么运行的

.I.!    Program. Input: Q
.I.!GQ  Implicit variable fill
.I      Find x such that:
  .!G    gamma(x+1)
     Q   == Q
        Implicitly print

5

MATL,13字节

1`1e-5+tQYgG<

这会1e-5从开始使用线性搜索1。因此它非常慢,并且在联机编译器中超时。

要进行测试,以下链接用代替了1e-5精度要求1e-2在线尝试!

说明

1        % Push 1 (initial value)
`        % Do...while
  1e-5   %   Push 1e-5
  +      %   Add
  t      %   Duplicate
  QYg    %   Pi function (increase by 1, apply gamma function)
  G<     %   Is it less than the input? If so: next iteration
         % End (implicit)
         % Display (implicit)

3

GeoGebra,25个字节

NSolve[Gamma(x+1)=A1,x=1]

输入CAS输入,并期望在电子表格单元格中输入数字A1。返回形式为一个元素的数组{x = <result>}

这是执行的gif:

执行程序

怎么运行的

N总的来说Solve,以下方程式为:Gamma(x+1)=A1,具有起始值x=1


是否可以保证返回正数,它是否适用于1.5(打破了几个答案)?
Pavel

@Pavel我可以确认它适用于1.5。我还无法找出GeoGebra使用哪种算法进行数值求解,但x=1对于我尝试的每个值,的初始值都给出了完全肯定的答案。
TheBikingViking

2

MATLAB,59个字节

@(x)fminsearch(@(t)(gamma(t+1)-x)^2,1,optimset('TolF',eps))

这是一个匿名函数,该函数在Pi函数及其输入(从到)之间找到平方差的最小化方1,且公差很小(由给出eps),以实现所需的精度。

测试案例(在Matlab R2015b上运行):

>> @(x)fminsearch(@(t)(gamma(t+1)-x)^2,1,optimset('TolF',eps))
ans = 
    @(x)fminsearch(@(t)(gamma(t+1)-x)^2,1,optimset('TolF',eps))
>> f = ans; format long; f(120), f(10), f(3.14), f(2017)
ans =
   5.000000000000008
ans =
   3.390077650547032
ans =
   2.448151165246967
ans =
   6.538472664321318

您可以在线尝试在Octave中,但是不幸的是,某些结果缺少所需的精度。


2

86 33字节

((]-(-~^.@!)%[:^.@!D.1])^:_>:)@^.

将牛顿方法与Log Pi配合使用以避免溢出。

这是以前使用斯特林近似值计算对数Gamma的版本。可以增加步长(1e3)和对数伽玛(3)中的项数,以提高性能的准确性。

3 :'(-(k-~g)%%&1e3(g=:((%~12 _360 1260 p.&:%*:)+-+^~-&^.%:@%&2p1)@>:)D:1])^:_>:k=:^.y'

即时计算系数项的另一个版本

3 :'(-((-^.y)+g)%%&1e3(g=:((%~(((%1-^@-)t:%]*<:)+:>:i.3)p.%@*:)+(*^.)-]+-:@^.@%&2p1)@>:)D:1])^:_>:^.y'

在线尝试!并看到条款趋同

说明

((]-(-~^.@!)%[:^.@!D.1])^:_>:)@^.  Input: float y
(                            )@^.  Operate on log(y)
                           >:        Increment, the initial guess is log(y)+1
 (                     )^:_          Repeat until convergence starting with x = log(y)+1
                      ]                Get x
               ^.@!                    The log Pi verb
             [:    D.1                 Approximate its first derivative at x
       ^.@!                            Apply log Pi to x
     -~                                Subtract log(y) from it
            %                          Divide it by the derivative
  ]-                                   Subtract it from x and use as next value of x

2

Mathematica,21个字节

FindRoot[#-x!,{x,1}]&

FindRoot 有初始值时在内部应用牛顿法。

下面的两种方法直接应用牛顿法。

使用FixedPoint 45字节的替代方法

FixedPoint[#-(#!-y)/Gamma'[#+1]&,Log[y=#]+1]&

由于Mathematica可以直接计算导数而不是近似导数,因此可以更精确地实现牛顿法来解决此问题。

重复使用规则替换会更短,但是它可以执行多少次迭代有一个限制(65536),而FixedPoint没有限制。

替代使用规则,38个字节

Log[y=#]+1//.x_->x-(x!-y)/Gamma'[x+1]&

图片


1

果冻,34个字节

Ḋ!Æl_®
ȷİ‘×;µ!ÆlI÷I÷@Ç_@ḊḢ
Æl©‘ÇÐĿ

在线尝试!在它们收敛时查看中间值

J的牛顿法和微分逼近(割线法)的组合的实现,用于计算Πn)。

为了避免溢出,它改为求解log(Πn))的逆。

它以初始猜测x 0 = y +1开始,其中y = log(Πn))。然后使用x n +1 = x n-(log(Πx n))- y)/(log((Π(1.001 * x n))-log(Πx n)))/ 迭代直到迭代(0.001 * x n))。


3
输入出现错误1.5
Luis Mendo

@LuisMendo哇,真是太好了!发生这种情况是因为其中一个中间值是〜65807,这是应用gamma后的巨大值,并且Python溢出。由于J依赖于相同的计算,因此也会发生同样的情况。
英里

1

PARI / GP,30个字节

x->solve(t=1,x+1,gamma(t+1)-x)

1和之间找到解决方案x+1。不幸的是,x像这样的输入上限还不够大1.5


1

Mathematica,26个字节

Mathematica的另一个解决方案!

方程求解总是可以转化为最小化问题。

NArgMin[{(#-x!)^2,x>0},x]&

查找使方程左右两侧之间的差异最小的参数。

使用NArgMin而不是NMinimize会强制输出仅是所需结果,而不是通常的基于规则的冗长输出(并且节省了一个字节!)


0

C与libm,111

更新 -固定为输入1.5。

f(double *z){double u=2**z,l=0,g=u,p=0;for(;log(fabs(g-p))>-14;)p=g,g=(u+l)/2,u=tgamma(g+1)>*z?g:(l=g,u);*z=g;}

gamma(x+1)是在所讨论范围内的单调递增函数,shis只是二进制搜索,直到连续值之间的差很小。起始下限为0和起始上限为2*x

输入和输出通过指向传递给该函数的double的指针进行。

我很确定这可以打得更深-特别是我认为我不需要4次本地双打,但是到目前为止,我还没有找到减少这种情况的简便方法。

在线尝试 -构建(与libm链接)并在bash脚本中运行。

轻度松懈:

f(double *z){
    double u=2**z,l=0,g=u,p=0;
    for(;log(fabs(g-p))>-14;){
        p=g;
        g=(u+l)/2;
        u=tgamma(g+1)>*z?g:(l=g,u);*z=g;
    }
}
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.