Encontrar raíces integrales de un polinomio


19

Desafío

El desafío es escribir un programa que tome los coeficientes de cualquier ecuación polinómica de n grados como entrada y devuelva los valores integrales de x para los que la ecuación es verdadera. Los coeficientes se proporcionarán como entrada en el orden de potencia decreciente o creciente. Puede asumir que todos los coeficientes son enteros .

Entrada y salida

La entrada será los coeficientes de la ecuación en orden decreciente o creciente de potencia. El grado de la ecuación, es decir, la potencia máxima de x, es siempre 1 menor que el total de elementos en la entrada.

Por ejemplo:

[1,2,3,4,5] -> represents x^4 + 2x^3 + 3x^2 + 4x + 5 = 0 (degree = 4, as there are 5 elements)
[4,0,0,3] -> represents 4x^3 + 3 = 0 (degree = 3, as there are 3+1 = 4 elements)

Su salida debe ser solo los distintos valores integrales de x que satisfacen la ecuación dada. Todos los coeficientes de entrada son enteros y el polinomio de entrada no será un polinomio cero . Si no hay una solución para la ecuación dada, entonces la salida no está definida.

Si una ecuación tiene raíces repetidas, muestre esa raíz en particular solo una vez. Puede generar los valores en cualquier orden. Además, suponga que la entrada contendrá al menos 2 números.

Ejemplos

[1,5,6] -> (-3,-2)
[10,-42,8] -> (4)
[1,-2,0] -> (0,2)
[1, 1, -39, -121, -10, 168] -> (-4, -3, -2, 1, 7)
[1, 0, -13, 0, 36] -> (-3, -2, 2, 3)
[1,-5] -> (5)
[1,2,3] -> -

Tenga en cuenta que la ecuación en el segundo ejemplo también tiene la raíz 0.2, pero no se muestra ya que 0.2 no es un número entero.

Puntuación

Este es el , por lo que gana el código más corto (en bytes).


77
Nota: Antes de votar para cerrar, considere que esta pregunta no es un duplicado de esta . Puedo pensar en al menos un enfoque para este problema que no será trivialmente modificable para el otro desafío (aunque no estoy diciendo qué; eso te queda a ti; P).
Erik the Outgolfer

¿Podemos suponer que solo necesitamos devolver raíces dentro de los límites enteros de nuestro lenguaje? ¿O debería funcionar el algoritmo incluso si se aumentara el rango de tipo entero de idiomas, pero el comportamiento se mantuvo igual?
Agradable

1
¿Podemos usar también un tipo de polinomio nativo si su idioma los admite?
flawr

1
¿Se aceptan programas que se ejecutan para siempre si no hay soluciones?
Jack M

1
Eso es para mantener las cosas simples.
Manish Kundu

Respuestas:


6

MATL , 13 12 bytes

|stE:-GyZQ~)

Pruébalo en línea!

Esto usa el hecho que, para coeficientes enteros, el valor absoluto de cualquier raíz es estrictamente menor que la suma de los valores absolutos de los coeficientes.

Explicación

Considere la entrada [1 5 6]como un ejemplo.

|    % Implicit input. Absolute value
     % STACK: [1 5 6]
s    % Sum
     % STACK: 12
t    % Duplicate
     % STACK: 12, 12
E    % Multiply by 2
     % STACK: 12, 24
:    % Range
     % STACK: 12, [1 2 ... 23 24]
-    % Subtract, elemet-wise
     % STACK: [11 10 ... -11 -12]
G    % Push input again
     % STACK: [11 10 ... -11 -12], [1 5 6]
y    % Duplicate from below
     % STACK: [11 10 ... -11 -12], [1 5 6], [11 10 ... -11 -12]
ZQ   % Polyval: values of polynomial at specified inputs
     % STACK: [11 10 ... -11 -12], [182 156 ... 72 90]
~    % Logical negation: turns nonzero into zero
     % STACK: [11 10 ... -11 -12], [0 0 ... 0] (contains 1 for roots)
)    % Index: uses second input as a mask for the first. Implicit display
     % STACK: [-3 -2]

3
Como alternativa al teorema de Rouche, el teorema de las raíces racionales también sería suficiente para justificar el límite que usaste. Según el teorema de las raíces racionales, todas las raíces enteras están limitadas en valor absoluto por el máximo de los valores absolutos de los coeficientes, un límite más estricto que la suma. O incluso más estricto, por el valor absoluto del "último" coeficiente distinto de cero, es decir, el coeficiente de la potencia más pequeña de x que tiene un coeficiente distinto de cero. (Probablemente no ayude a guardar ningún byte, solo una prueba alternativa ya que el RRT es probablemente más familiar que Rouche para la mayoría de las personas). :)
Mathmandan

1
@mathmandan ese enfoque es tres bytes más largo: Pruébelo aquí , aunque estoy seguro de que me he perdido un truco o dos
Giuseppe

@Giuseppe Gracias a ambos. Quizás X>t_w&:GyZQ~), pero aún 13 bytes
Luis Mendo

1
... pero encontré una alternativa más corta para el rango
Luis Mendo

5

Casco , 10 9 bytes

-1 byte gracias a Zgarb

uSȯf¬`Bṁṡ

Pruébalo en línea!

Explicación

       ṁṡ   Concatenate together the symmetric ranges of each coefficient
            (It is guaranteed that the integer roots lie in the range [-n..n],
                        where n is the coefficient with the largest magnitude)
 Sȯf        Find all the values in that range which
    ¬       are zero
     `B     when plugged through the polynomial
            (Base conversion acts as polynomial evaluation)
u           De-duplicate the roots

Podrías hacerlo en ṁṡlugar de oṡ►asi deduplicas más tarde.
Zgarb

@ Zgarb Muy bien! Gracias
H.PWiz

5

Haskell , 54 bytes

f l|t<-sum$abs<$>l=[i|i<-[-t..t],foldl1((+).(i*))l==0]

Pruébalo en línea!

Fuerza bruta y división sintética.

Ungolfed con UniHaskell y-XUnicodeSyntax

import UniHaskell

roots     Num a  [a]  [a]
roots xs = [r | r  -bound  bound, foldl1 ((+)  (r ×)) xs  0]
             where bound = sum $ abs § xs

Solución alternativa, 44 bytes.

Crédito a nimi.

f l=[i|i<-[minBound..],foldl1((+).(i*))l==0]

Buena suerte al intentarlo en línea , ya que esto verifica cada número en Intel rango de un.


Se puede recorrer imás [minBound..]y soltar toda la tcosa. Llame fcon Intlistas explícitas , por ej f [1::Int,5,6]. Por supuesto, esto no termina en un tiempo razonable.
nimi

@nimi ¿Por qué se detendría eso? ¿No sería un bucle infinito?
Totalmente humano el

No, los Boundedtipos se detienen en maxBound, por ejemplo print [minBound::Bool ..].
nimi

4

Python 2 + numpy, 95 93 91 103 93 91 82 bytes

-2 bytes gracias a ovs
gracias Luis Mendo por los límites superior / inferior de las raíces
-10 bytes gracias al Sr. Xcoder

from numpy import*
def f(r):s=sum(fabs(r));q=arange(-s,s);print q[polyval(r,q)==0]

Pruébalo en línea!



@LuisMendo sí.
Rod

3
Nuestro consenso actual parece ser que los programas siempre deben terminar, a menos que el desafío indique lo contrario.
Zgarb

@Zgarb allí, arreglado!
Rod

Usar numpy.polyvalguarda bastantes bytes
Sr. Xcoder

4

Wolfram Language (Mathematica) , 50 47 42 25 27 bytes

{}⋃Select[x/.Solve[#~FromDigits~x==0],IntegerQ]&

Pruébalo en línea!

Actualización: usando el hecho de Luis Mendo, jugó otros 3 bytes

Pick[r=Range[s=-Tr@Abs@#,-s],#~FromDigits~r,0]&

Volviendo más descuidado con los límites, podemos reducir estos 5 bytes más por @No la sugerencia de un árbol:

Pick[r=Range[s=-#.#,-s],#~FromDigits~r,0]&

Después de publicar esto, OP comentó que permite "polinomios nativos", así que aquí hay una solución de 25 bytes que acepta el polinomio como entrada. Esto funciona porque por defecto Mathematica factoriza polinomios sobre los enteros, y cualquier raíz racional aparece en una forma como m*x+besa falla la coincidencia de patrones.

Cases[Factor@#,b_+x:>-b]&

Como señaló @alephalpha, esto fallará en el caso de que cero sea una raíz, por lo que para solucionarlo podemos usar el Optionalsímbolo:

Cases[Factor@#,b_:0+x:>-b]&

Esto analiza Mathematica 11.0.1 pero falla y requiere un conjunto adicional de paréntesis b_:0en la versión 11.2. Esto ocupa una copia de seguridad de hasta 27 bytes, más dos más después de la versión 11.0.1. Parece que se puso una "solución" aquí

Pruébalo en línea!


1
Creo que puede usar en #.#lugar de Tr@Abs@#: es un límite peor pero menos bytes.
No es un árbol

1
OP dijo en un comentario que podría usar el tipo de polinomio nativo de su idioma si existe. No conozco bien Mathematica pero imagino que hay uno ... ¿Eso ahorraría bytes?
No, no se muestra mi nombre real el


1
@alephalpha, fijo.
Kelly Lowder


3

Wolfram Language (Mathematica) , 33 26 31 bytes

Se corrigió un error observado por Kelly Lowder en los comentarios.

x/.{}⋃Solve[#==0,x,Integers]&

Pruébalo en línea!

Soluciones incorrectas anteriores:

Me acabo de dar cuenta de que para una solución sin número entero, la salida no está definida en lugar de una lista vacía; eso permite eliminar algunos bytes.

x/.Solve[#==0,x,Integers]&

Pruébalo en línea!

Ahora, si no existe una solución entera, la función devuelve x .

Previamente:

x/.Solve[#==0,x,Integers]/.x->{}&

Pruébalo en línea!


Esto falla como se indica actualmente con 1,2,1, ya que repite la raíz y el OP dijo que tenían que ser distintos. Necesitas Unionarreglar eso.
Kelly Lowder

@KellyLowder: Ah, me perdí eso. Pero entonces, también faltaba en los casos de prueba dados.
celtschk

@KellyLowder: ahora lo he arreglado. En caso de que haya rechazado debido a esto, ¿puede revertirlo?
celtschk

@cellschk, sí, listo.
Kelly Lowder

29 bytes mediante el uso de una característica no documentada de Solve: la lista de variables se puede omitir.
Romano

3

R , 61 59 bytes

¡Un agradecimiento especial a @mathmandan por señalar mi enfoque (incorrecto) podría salvarse y jugar golf!

function(p)(x=-(t=p[!!p][1]):t)[!outer(x,seq(p)-1,"^")%*%p]

Pruébalo en línea!

Toma la entrada como una lista de coeficientes en orden creciente , es decir, c(-1,0,1)representa-1+0x+1x^2 .

Usando el teorema de la raíz racional, el siguiente enfoque casi funciona, para 47 bytes:

function(p)(x=-p:p)[!outer(x,seq(p)-1,"^")%*%p]

Pruébalo en línea!

-p:pgenera un rango simétrico (con una advertencia) usando sólo el primer elemento de p, a_0. Según el teorema de la raíz racional , todas las raíces racionales Pdeben tener la forma p/qen que pdivide a_0y qdividea_n (más o menos). Por lo tanto, usando sólo a_0es suficiente para |a_0|>0, como para cualquier q, |p/q|<=a_0. Sin embargo, cuando a_0==0, como entonces, cualquier entero se divide 0, y por lo tanto esto falla.

Sin embargo, Mathmandan señala que realmente, en este caso, esto significa que hay un factor constante x^kque puede ser factorizado, y, suponiendo que ksea ​​máximo, vemos que

P(x) = x^k(a_k + a_{k+1}x + ... a_n x^{n-k}) = x^k * Q(x)

Luego aplicamos el teorema de la raíz racional a Q(x), y comoa_k se garantiza que no es cero por la maximidad de k, a_kproporciona un límite ordenado para las raíces enteras de Q, y las raíces de Pson las raíces deQ junto con cero, por lo que tendremos todo el entero raíces deP mediante la aplicación de este método.

Esto es equivalente a encontrar el primer coeficiente distinto de cero del polinomio t=p[!!p][1]y usarlo en lugar de lo ingenuo p[1]como límites. Además, desde el rango-t:t siempre contiene cero, se aplicaP a este rango aún nos daría cero como raíz, si es que lo es.

sin golf:

function(polynom) {
 bound <- polynom[polynom != 0][1]             #first nonzero value of polynom
 range <- -bound:bound                         #generates [-bound, ..., bound]
 powers <- outer(range,seq_along(p) - 1, "^")  #matrix where each row is [n^0,n^1,n^2,...,n^deg(p)]
 polyVals <- powers %*% polynom                #value of the polynomial @ each point in range
 return(range[polyVals == 0])                  #filter for zeros and return
}


(Creo que podría usar los maxvalores absolutos en lugar de los valores sum; esto no cambiaría el recuento de bytes, pero debería mejorar el rendimiento). De todos modos, sí, lástima que la versión más corta no funcione a_0==0. ¿Hay algún camino corto en R para buscar el primer coeficiente distinto de cero (con potencias ascendentes) y utilizarlo en su lugar? Esto correspondería a factorizar la mayor cantidad posible de x primero (por supuesto, entonces también tendría que recordar la salida 0, lo que presumiblemente costaría algunos bytes)
Mathmandan

@mathmandan maxsería más eficiente, pero para su segundo punto, ya que no tengo que preocuparme por la salida, 0ya que es generado por el rango -t:t(¿dónde testá el primer coeficiente distinto de cero), ahorra 2 bytes!
Giuseppe

¡Oh, muy bien! (Y una hermosa explicación también.)
Mathmandan

2

Jalea , 8 bytes

ASŒRḅ@Ðḟ

Pruébalo en línea! o como una suite de prueba!

¿Cómo?

ASŒRḅ @ Ðḟ || Programa completo (enlace monádico).

AS || Suma los valores absolutos.
  ŒR || Y cree el rango simétrico inclusivo a partir de su valor negativo.
       Ðḟ || Y descarte aquellos que producen un valor verdadero ...
     ḅ @ || Al conectarlos al polinomio (usa conversión de base).

Basado en la respuesta de Luis . Una alternativa .


¿Hay algo que me falta sobre tomar el orden inverso (permitido) y hacer Ær+.Ḟ?
Jonathan Allan el

Estoy un poco confundido ya que la respuesta de Python con numpy tampoco lo está haciendo, y creo que me he perdido algún caso extremo.
Jonathan Allan el

@JonathanAllan Como esperaba, el tuyo falla [1,2,3].
Sr. Xcoder

"Si no hay una solución para la ecuación dada, entonces el resultado no está definido"
Jonathan Allan

@JonathanAllan Pero no fallar para [10,-42,8], ¿verdad?
Sr. Xcoder

2

Octava , 59 49 bytes

@(p)(x=-(t=p(~~p)(end)):sign(t):t)(!polyval(p,x))

Pruébalo en línea!

Este es un puerto de mi R respuesta . La única diferencia es que tengo que usar explícitamente sign(t)y endgenerar el rango, y que tiene polyvalque calcular el polinomio.

Toma la entrada como un vector fila de coeficientes en orden decreciente.



2

C (gcc) , 127 126 123 bytes

x,X,j,m,p;f(A,l)int*A;{for(m=j=0;j<l;m+=abs(A[j++]));for(x=~m;X=x++<m;p||printf("%d,",x))for(p=j=0;j<l;X*=x)p+=A[l-++j]*X;}

Pruébalo en línea!


Explicación

C (gcc) , 517 bytes

x,X,j,m,p;                      // global integer variables
f(A,l)int*A;{                   // define function, takes in integer array pointer and length
 for(m=j=0;j<l;m+=abs(A[j++])); // loop through array, sum up absolute values
  for(x=~m;X=x++<m;             // loop through all values x in [-m, m], prime X
   p||printf("%d,",x))          // at loop's end, print x value if polynomial value is zero
    for(p=j=0;j<l;X*=x)         // loop through coefficients
     p+=A[l-++j]*X;}            // build polynomial

Pruébalo en línea!


l+~j++se puede jugar al golfl-++j
Kevin Cruijssen

@KevinCruijssen Muchas gracias.
Jonathan Frech

@ceilingcat Gracias.
Jonathan Frech

1

Java 8, 141 140 bytes

a->{int l=a.length,s=0,i,r,f,p;for(int n:a)s+=n<0?-n:n;for(r=~s;r++<s;System.out.print(p==0?r+",":""))for(p=i=0,f=1;i<l;f*=r)p+=a[l-++i]*f;}

Inspirado por la respuesta Python 2 de @Rod (su versión de 82 bytes) .

Desafío divertido! Ciertamente aprendí mucho al investigar sobre polinomios y ver cómo otros aquí lo han hecho.

Explicación:

Pruébalo en línea.

a->{                   // Method with integer-array parameter and no return-type
  int l=a.length,      //  The length of the input-array
      s=0,             //  Sum-integer, starting at 0
      i,               //  Index integer
      r,               //  Range-integer
      f,               //  Factor-integer
      p;               //  Polynomial-integer
  for(int n:a)         //  Loop over the input-array
    s+=n<0?-n:n;       //   And sum their absolute values
  for(r=~s;r++<s;      //  Loop `r` from `-s` up to `s` (inclusive) (where `s` is the sum)
      System.out.print(p==0?r+",":""))
                       //    After every iteration: print the current `r` if `p` is 0
    for(p=i=0,         //   Reset `p` to 0
        f=1;           //   and `f` to 1
        i<l;           //   Loop over the input-array again, this time with index (`i`)
        f*=r)          //     After every iteration: multiply `f` with the current `r`
      p+=              //    Sum the Polynomial-integer `p` with:
         a[l-++i]      //     The value of the input at index `l-i-1`,
                 *f;}  //     multiplied with the current factor `f`



0

JavaScript (ES6), 97 bytes

a=>[...Array((n=Math.max(...a.map(Math.abs)))-~n)].map(_=>n--).filter(i=>!a.reduce((x,y)=>x*i+y))

Toma coeficientes en orden decreciente de potencia y produce resultados en orden descendente.



Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.