Función Pi inversa

17

La función Pi es una extensión del factorial sobre los reales (o incluso números complejos). Para enteros n , Π (n) = n! , pero para obtener una definición sobre los reales, la definimos utilizando una integral:

Pi (z) = integral t desde 0 hasta infinito e ^ -tt ^ z dt

En este desafío invertiremos la función Π .

Dado un número real z ≥ 1 , encuentre x positivo tal que Π (x) = z . Su respuesta debe ser precisa para al menos 5 dígitos decimales.


Ejemplos:

120 -> 5.0000
10 -> 3.39008
3.14 -> 2.44815
2017 -> 6.53847
1.5 -> 1.66277
orlp
fuente
44
Tenga en cuenta que con mayor frecuencia las personas usan la función Gamma (Γ). Π (x) = Γ (x + 1) . Pero IMO Γ es una abominación desplazada, y Π es la verdadera extensión del factorial.
orlp
1
Bueno, esa expansión de la serie es suficiente para asustarme ... i.imgur.com/ttgzDSJ.gif
Urna de pulpo mágico
1
Todos los ejemplos que da también tienen otras soluciones, por ejemplo 120 -> -0.991706. Esto se debe a que Π (x) va al infinito como x va a -1 desde la derecha. Quizás quieras decir que x> 0 también.
Greg Martin
@GregMartin Agregado también.
orlp
1
Hay algunas razones para preferir la versión modificada, a pesar de que parece poco natural. Vea, por ejemplo, esta respuesta en MathOverflow y otras en esa página.
Ruslan

Respuestas:

8

Mathematica, 17 15 27 bytes

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

La salida se ve como {{x -> n}}, ¿dónde nestá la solución?

Pavel
fuente
7

Pyth, 4 bytes

.I.!

Un programa que toma la entrada de un número e imprime el resultado.

Banco de pruebas

Cómo funciona

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

MATL , 13 bytes

1`1e-5+tQYgG<

Esto utiliza búsqueda lineal en pasos de 1e-5comenzar en 1. Por lo tanto, es terriblemente lento y se agota el tiempo de espera en el compilador en línea.

Para probarlo, el siguiente enlace reemplaza el 1e-5requisito de precisión por 1e-2.Pruébalo en línea!

Explicación

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)
Luis Mendo
fuente
3

GeoGebra , 25 bytes

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

Ingresado en la entrada CAS, y espera la entrada de un número en la celda de la hoja de cálculo A1 . Devuelve una matriz de un elemento del formulario {x = <result>}.

Aquí hay un gif de la ejecución:

Ejecución de progrma

Cómo funciona

Nnuméricamente Solvela siguiente ecuación:, Gamma(x+1)=A1con valor inicial x=1.

TheBikingViking
fuente
¿Se garantiza que devolverá un número positivo y funciona para 1.5, que ha roto varias respuestas?
Pavel
@Pavel Puedo confirmar que funciona 1.5. No he podido averiguar qué algoritmo utiliza GeoGebra para la resolución numérica, pero el valor inicial de x=1ha dado respuestas puramente positivas para cada valor que he probado.
TheBikingViking
2

MATLAB, 59 bytes

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

Esta es una función anónima que encuentra el minimizador de la diferencia al cuadrado entre la función Pi y su entrada, comenzando en 1 , con una tolerancia muy pequeña (dada por eps) para lograr la precisión deseada.

Casos de prueba (ejecutados en 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

Puede probarlo en línea en Octave, pero desafortunadamente algunos de los resultados carecen de la precisión requerida.

Luis Mendo
fuente
2

J, 86 33 bytes

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

Utiliza el método de Newton con log Pi para evitar el desbordamiento.

Esta es la versión anterior que calcula el registro Gamma utilizando la aproximación de Stirling. El tamaño del paso (1e3) y el número de términos en el registro Gamma (3) se pueden aumentar para obtener posiblemente una mayor precisión a costa del rendimiento.

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

Otra versión que calcula los términos del coeficiente sobre la marcha.

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

Pruébalo en línea! y para ver los términos converger .

Explicación

((]-(-~^.@!)%[:^.@!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
millas
fuente
2

Mathematica, 21 bytes

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

FindRoot aplica el método de Newton internamente cuando hay un valor inicial.

Los dos métodos a continuación aplican el método de Newton directamente.

Alternativa usando FixedPoint 45 bytes

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

Una implementación más precisa del método de Newton para resolver esto ya que Mathematica puede calcular la derivada directamente en lugar de aproximarla.

El uso de reglas para reemplazar repetidamente sería más corto, pero hay un límite (65536) a la cantidad de iteraciones que puede realizar que podrían ser alcanzadas, mientras FixedPointque no tiene un límite.

Alternativa usando reglas, 38 bytes

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

Imagen

millas
fuente
1

Jalea , 34 bytes

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

Pruébalo en línea! o Ver los valores intermedios a medida que convergen .

Una implementación de la combinación de J del método de Newton y la aproximación derivada (método secante) para calcular la inversa de Π ( n ).

En su lugar, resuelve el inverso de log ( Π ( n )) para evitar el desbordamiento.

Comienza con una suposición inicial x 0 = y +1 donde y = log ( Π ( n )). Luego itera hasta la convergencia usando x n +1 = x n - (log ( Π ( x n )) - y ) / (log (( Π (1.001 * x n )) - log ( Π ( x n ))) / (0,001 * x n )).

millas
fuente
3
Me sale un error con la entrada1.5
Luis Mendo
@LuisMendo ¡Guau, es una buena captura! Ocurre porque uno de los valores intermedios es ~ 65807, que es un valor enorme después de que se aplica gamma, y ​​Python se desborda. Lo mismo ocurre en J ya que se basa en el mismo cálculo.
millas
1

PARI / GP, 30 bytes

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

Encuentra la solución entre 1y x+1. Desafortunadamente, xno es lo suficientemente grande como límite superior para entradas como 1.5.

Christian Sievers
fuente
1

Mathematica, 26 Bytes

¡Otra solución más de Mathematica!

La resolución de ecuaciones siempre se puede convertir en un problema de minimización.

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

Encuentra el argumento que minimiza la diferencia entre los lados izquierdo y derecho de la ecuación.

El uso de NArgMin en lugar de NMinimize obliga a la salida a ser solo el resultado deseado en lugar de la salida basada en reglas detalladas habituales (¡y ahorra un byte!)

Kelly Lowder
fuente
0

C con libm, 111

Actualización : corregida para la entrada 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)es una función monótonamente creciente en el rango en cuestión, es solo una búsqueda binaria hasta que la diferencia entre valores sucesivos es pequeña. El límite inferior inicial es 0y el límite superior inicial es 2*x.

La entrada y salida es a través de un puntero a un doble pasado a la función.

Estoy bastante seguro de que esto puede ser más profundo, en particular, no creo que necesite 4 dobles locales, pero hasta ahora no veo una manera fácil de reducir esto.

Pruébelo en línea : se compila (vincula con libm) y se ejecuta en un script bash.

Ligeramente no golfista:

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;
    }
}
Trauma digital
fuente