Trouver les racines intégrales d'un polynôme

19

Défi

Le défi consiste à écrire un programme qui prend en entrée les coefficients de toute équation polynomiale à n degrés et renvoie les valeurs intégrales de x pour lesquelles l'équation est vraie. Les coefficients seront fournis en entrée dans l'ordre de puissance décroissante ou croissante. Vous pouvez supposer que tous les coefficients sont des entiers .

Entrée et sortie

L'entrée sera les coefficients de l'équation en ordre décroissant ou croissant de puissance. Le degré de l'équation, c'est-à-dire la puissance maximale de x, est toujours inférieur de 1 au nombre total d'éléments dans l'entrée.

Par exemple:

[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)

Votre sortie ne doit être que les valeurs intégrales distinctes de x qui satisfont l'équation donnée. Tous les coefficients d'entrée sont des entiers et le polynôme d'entrée ne sera pas un polynôme nul . S'il n'y a pas de solution pour l'équation donnée, alors la sortie n'est pas définie.

Si une équation a des racines répétées, affichez cette racine particulière une seule fois. Vous pouvez sortir les valeurs dans n'importe quel ordre. Supposons également que l'entrée contienne au moins 2 chiffres.

Exemples

[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] -> -

Notez que l'équation dans le deuxième exemple a également la racine 0,2, mais elle n'est pas affichée car 0,2 n'est pas un entier.

Notation

C'est le , donc le code le plus court (en octets) gagne!

Manish Kundu
la source
7
Remarque: Avant de voter pour clore, veuillez considérer que cette question n'est pas un double de celle-ci . Je peux penser à au moins une approche de ce problème qui ne sera pas trivialement modifiable pour l'autre défi (bien que je ne dis pas quoi; cela vous reste; P).
Erik the Outgolfer le
Pouvons-nous supposer que nous avons seulement besoin de renvoyer des racines à l'intérieur des limites entières de notre langage? Ou l'algorithme devrait-il fonctionner même si la plage de types d'entiers des langues a été augmentée, mais le comportement est resté le même.
Janurous
1
Pouvons-nous également utiliser un type de polynôme natif si votre langue les prend en charge?
flawr
1
Les programmes fonctionnent-ils pour toujours si aucune solution n'est acceptée?
Jack M
1
C'est pour garder les choses simples.
Manish Kundu

Réponses:

6

MATL , 13 12 octets

|stE:-GyZQ~)

Essayez-le en ligne!

Cela utilise le fait que, pour les coefficients entiers, la valeur absolue de toute racine est strictement inférieure à la somme des valeurs absolues des coefficients.

Explication

Considérez l'entrée [1 5 6]comme exemple.

|    % 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]
Luis Mendo
la source
3
Comme alternative au théorème de Rouche, le théorème des racines rationnelles suffirait également à justifier la limite que vous avez utilisée. Selon le théorème des racines rationnelles, toutes les racines entières sont limitées en valeur absolue par le maximum des valeurs absolues des coefficients, une limite plus stricte que la somme. Ou encore plus serré, par la valeur absolue du "dernier" coefficient non nul - c'est-à-dire le coefficient de la plus petite puissance de x qui a un coefficient non nul. (Cela n'aide probablement pas à sauver des octets, juste une preuve alternative car le RRT est probablement plus familier que Rouche à la plupart des gens.) :)
mathmandan
1
@mathmandan cette approche est plus longue de trois octets: essayez-la ici , même si je suis sûr que j'ai raté une ou deux astuces
Giuseppe
@Giuseppe Merci à tous les deux. Peut X>t_w&:GyZQ~)- être , mais toujours 13 octets
Luis Mendo
1
... mais j'ai trouvé une alternative plus courte pour la gamme
Luis Mendo
5

Husk , 10 9 octets

-1 octet grâce à Zgarb

uSȯf¬`Bṁṡ

Essayez-le en ligne!

Explication

       ṁṡ   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
H.PWiz
la source
Vous pourriez faire ṁṡau lieu de oṡ►asi vous dédupliquez plus tard.
Zgarb
@Zgarb Very nice! Merci
H.PWiz
5

Haskell , 54 octets

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

Essayez-le en ligne!

Force brute et division synthétique.

Ungolfed avec UniHaskell et-XUnicodeSyntax

import UniHaskell

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

Solution alternative, 44 octets

Crédit à Nimi.

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

Bonne chance pour l' essayer en ligne , car cela vérifie chaque numéro dans Intla plage d'un.

totalement humain
la source
Vous pouvez itérer iplus [minBound..]déposer toute tchose. Appelez favec des Intlistes explicites , par exemple f [1::Int,5,6]. Bien sûr, cela ne se termine pas dans un délai raisonnable.
nimi
@nimi Pourquoi cela s'arrêterait-il jamais? Ne boucle-t-il pas à l'infini?
totalement humain le
Non, les Boundedtypes s'arrêtent à maxBound, par exemple print [minBound::Bool ..].
nimi
4

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

-2 octets grâce aux ovs
merci Luis Mendo pour les bornes supérieures / inférieures des racines
-10 octets merci à M. Xcoder

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

Essayez-le en ligne!

Barre
la source
91 octets
ovs
@LuisMendo oui.
Rod
3
Notre consensus actuel semble être que les programmes doivent toujours se terminer, sauf indication contraire.
Zgarb
@Zgarb là, réparé!
Rod
L'utilisation numpy.polyvaléconomise pas mal d'octets
M. Xcoder
4

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

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

Essayez-le en ligne!

Mise à jour: en utilisant le fait de Luis Mendo, a joué encore 3 octets

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

De plus en plus bâclé avec les limites, nous pouvons réduire ces 5 octets supplémentaires par @Pas une suggestion d'arbre:

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

Après avoir posté cela, OP a commenté l'autorisation des "polynômes natifs", voici donc une solution de 25 octets qui accepte le polynôme en entrée. Cela fonctionne parce que par défaut Mathematica factorise les polynômes sur les entiers, et toutes les racines rationnelles apparaissent sous une forme comme m*x+bcelle-ci échoue la correspondance de modèle.

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

Comme l'a souligné @alephalpha, cela échouera dans le cas où zéro est une racine, donc pour corriger cela, nous pouvons utiliser le Optionalsymbole:

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

Cela analyse finement Mathematica 11.0.1 mais échoue et nécessite un ensemble supplémentaire de parenthèses b_:0dans la version 11.2. Cela prend jusqu'à 27 octets, plus deux autres après la version 11.0.1. Il semble qu'un "correctif" ait été ajouté ici

Essayez-le en ligne!

Kelly Lowder
la source
1
Je pense que vous pouvez utiliser à la #.#place de Tr@Abs@#: c'est une pire limite mais moins d'octets.
Pas un arbre le
1
OP a déclaré dans un commentaire que vous pourriez utiliser le type de polynôme natif de votre langue s'il en existe un. Je ne connais pas bien Mathematica mais j'imagine qu'il y en a un ... Est-ce que cela économiserait des octets?
Non n'a pas montré mon vrai nom le
1
@alephalpha, fixe.
Kelly Lowder
3

Wolfram Language (Mathematica) , 33 26 31 octets

Correction d'une erreur notée par Kelly Lowder dans les commentaires.

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

Essayez-le en ligne!

Solutions incorrectes précédentes:

Je viens de remarquer que pour aucune solution entière, la sortie n'est pas définie au lieu d'une liste vide; cela permet de supprimer quelques octets.

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

Essayez-le en ligne!

Maintenant, si aucune solution entière n'existe, la fonction retourne x.

Précédemment:

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

Essayez-le en ligne!

celtschk
la source
Cela échoue comme indiqué actuellement avec 1,2,1 car il répète la racine et l'OP a dit qu'ils devaient être distincts. Vous devez Unioncorriger cela.
Kelly Lowder
@KellyLowder: Ah, j'ai raté ça. Mais ensuite, il manquait également dans les cas de test donnés.
celtschk
@KellyLowder: Je l'ai maintenant corrigé. Si vous avez voté pour cette raison, pouvez-vous s'il vous plaît revenir en arrière?
celtschk
@cellschk, c'est fait.
Kelly Lowder
29 octets en utilisant une fonctionnalité non documentée de Solve: la liste des variables peut être omise.
Roman
3

R , 61 59 octets

Un merci spécial à @mathmandan pour avoir souligné que mon approche (incorrecte) pouvait être sauvegardée et jouée au golf !

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

Essayez-le en ligne!

Prend l'entrée comme une liste de coefficients dans l' ordre croissant , c'est-à-dire, c(-1,0,1)représente -1+0x+1x^2.

En utilisant le théorème de la racine rationnelle, l'approche suivante fonctionne très bien, pour 47 octets:

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

Essayez-le en ligne!

-p:pgénère une série symétrique (avec une mise en garde) en utilisant uniquement le premier élément de p, a_0. Selon le théorème de la racine rationnelle , toutes les racines rationnelles de Pdoivent être de la forme p/qoù se pdivise a_0et se qdivise a_n(plus ou moins). Par conséquent, en utilisant seulement a_0suffit pour |a_0|>0, comme pour tout q, |p/q|<=a_0. Cependant, quand a_0==0, comme alors, tout entier se divise 0, et donc cela échoue.

Cependant, le mathmandan souligne que vraiment, dans ce cas, cela signifie qu'il y a un facteur constant x^kqui peut être pris en compte, et, en supposant qu'il kest maximal, nous voyons que

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

Nous appliquons ensuite le théorème de la racine rationnelle à Q(x), et comme il a_kest garanti qu'il est différent de zéro par la maximalité de k, a_kfournit une borne ordonnée pour les racines entières de Q, et les racines de Psont les racines de Qavec zéro, nous aurons donc tout l'entier racines de Pen appliquant cette méthode.

Cela revient à trouver le premier coefficient non nul du polynôme t=p[!!p][1]et à l'utiliser à la place du naïf p[1]comme limites. De plus, comme la plage -t:tcontient toujours zéro, l'appliquer Pà cette plage nous donnerait toujours zéro comme racine, si c'est le cas.

non 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
}

Giuseppe
la source
(Je pense que vous pouvez utiliser la maxvaleur absolue au lieu de la sum; cela ne changerait pas le nombre d'octets, mais cela devrait améliorer les performances.) Quoi qu'il en soit, dommage, la version courte ne fonctionne pas a_0==0. Existe-t-il un moyen court dans R de rechercher le premier coefficient (avec des puissances ascendantes) différent de zéro, et de l'utiliser à la place? Cela correspondrait à la suppression du plus grand nombre de x possible en premier (bien sûr, vous devriez alors vous rappeler de produire 0également, ce qui coûterait probablement quelques octets.)
mathmandan
@mathmandan maxserait plus efficace, mais pour votre deuxième point, comme je n'ai pas à me soucier de la sortie 0car il est généré par la plage -t:t(où test le premier coefficient non nul), il économise 2 octets!
Giuseppe
Ah, très bien! (Et une belle explication aussi.)
Mathmandan
2

Gelée , 8 octets

ASŒRḅ@Ðḟ

Essayez-le en ligne! ou comme suite de tests!

Comment?

ASŒRḅ @ Ðḟ || Programme complet (lien monadique).

AS || Additionnez les valeurs absolues.
  ŒR || Et créez la plage inclusive symétrique à partir de sa valeur négative.
       Ðḟ || Et jetez ceux qui donnent une valeur vraie ...
     ḅ @ || Lors de leur connexion au polynôme (utilise la conversion de base).

Basé sur la réponse de Luis . Une alternative .

M. Xcoder
la source
Y a-t-il quelque chose qui me manque dans le fait de prendre l'ordre inverse (autorisé) et de faire Ær+.Ḟ?
Jonathan Allan
Je suis légèrement confus car la réponse Python avec numpy ne le fait pas non plus, et je pense que j'ai raté un cas de bord.
Jonathan Allan
@JonathanAllan Comme je m'y attendais, le vôtre échoue [1,2,3].
M. Xcoder
"S'il n'y a pas de solution pour l'équation donnée, alors la sortie n'est pas définie"
Jonathan Allan
@JonathanAllan Mais il n'échouer pour , non? [10,-42,8]
M. Xcoder
2

Octave , 59 49 octets

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

Essayez-le en ligne!

Ce port est de ma réponse R . La seule différence est que je dois utiliser explicitement sign(t)et endgénérer la plage, et qu'elle doit polyvalcalculer le polynôme.

Prend l'entrée comme un vecteur de coefficients de ligne dans l'ordre décroissant.

Giuseppe
la source
2

Pari / GP , 31 octets

p->[x-a|a<-factor(p)[,1],a'==1]

Factorise le polynôme et sélectionne les facteurs dont les dérivées sont 1.

Essayez-le en ligne!

alephalpha
la source
2

C (gcc) , 127 126 123 octets

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;}

Essayez-le en ligne!


Explication

C (gcc) , 517 octets

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

Essayez-le en ligne!

Jonathan Frech
la source
l+~j++peut être joué au l-++j
golf
@KevinCruijssen Merci beaucoup.
Jonathan Frech
@ceilingcat Merci.
Jonathan Frech
1

Java 8, 141 140 octets

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;}

Inspiré par la réponse Python 2 de @Rod (sa version de 82 octets) .

Défi amusant! J'en ai certainement beaucoup appris en enquêtant sur les polynômes et en voyant comment d'autres ici l'ont fait.

Explication:

Essayez-le en ligne.

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`
Kevin Cruijssen
la source
0

JavaScript (ES6), 97 octets

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

Prend les coefficients dans l'ordre décroissant de puissance et les résultats sortent dans l'ordre décroissant.

Neil
la source
0

Nettoyer , 110 91 octets

import StdEnv
?p#s=sum p
=[i\\i<-[~s..s]|i<>0&&sum[e*i^t\\t<-reverse(indexList p)&e<-p]==0]

Essayez-le en ligne!

Οurous
la source