Trova le radici integrali di un polinomio


19

Sfida

La sfida è scrivere un programma che prende come input i coefficienti di qualsiasi equazione polinomiale di grado n e restituisce i valori integrali di x per i quali l'equazione è vera. I coefficienti saranno forniti come input nell'ordine di potenza decrescente o crescente. Puoi assumere che tutti i coefficienti siano numeri interi .

Ingresso e uscita

L'input sarà i coefficienti dell'equazione in ordine decrescente o crescente di potenza. Il grado dell'equazione, ovvero la potenza massima di x, è sempre 1 in meno rispetto al no totale degli elementi nell'input.

Per esempio:

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

L'output dovrebbe essere solo i valori integrali distinti di x che soddisfano l'equazione data. Tutti i coefficienti di input sono numeri interi e il polinomio di input non sarà un polinomio zero . Se non esiste una soluzione per l'equazione specificata, l'output non è definito.

Se un'equazione ha ripetute radici, visualizza quella radice solo una volta. È possibile generare i valori in qualsiasi ordine. Inoltre, supponiamo che l'input conterrà almeno 2 numeri.

Esempi

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

Si noti che l'equazione nel secondo esempio ha anche la radice 0.2, ma non viene visualizzata in quanto 0.2 non è un numero intero.

punteggio

Questo è , quindi vince il codice più breve (in byte)!


7
Nota: prima di votare per chiudere, ti preghiamo di considerare che questa domanda non è una copia di questa . Posso pensare ad almeno un approccio a questo problema che non sarà banalmente modificabile per l'altra sfida (anche se non sto dicendo cosa; che è lasciato a te; P).
Erik the Outgolfer,

Possiamo presumere che abbiamo solo bisogno di restituire radici all'interno dei limiti interi della nostra lingua? O dovrebbe funzionare l'algoritmo anche se l'intervallo di tipi interi delle lingue è stato aumentato, ma il comportamento è rimasto lo stesso.
Οuroso

1
Possiamo anche usare un tipo polinomiale nativo se la tua lingua li supporta?
flawr

1
I programmi funzionano per sempre se non ci sono soluzioni accettate?
Jack M

1
Questo per mantenere le cose semplici.
Manish Kundu,

Risposte:


6

MATL , 13 12 byte

|stE:-GyZQ~)

Provalo online!

Questo utilizza il fatto che, per coefficienti interi, il valore assoluto di qualsiasi radice è strettamente inferiore alla somma dei valori assoluti dei coefficienti.

Spiegazione

Considera l'input [1 5 6]come esempio.

|    % 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
In alternativa al teorema di Rouche, il teorema delle radici razionali sarebbe anche sufficiente per giustificare il limite che hai usato. Secondo il teorema delle radici razionali, tutte le radici intere sono delimitate in valore assoluto dal massimo dei valori assoluti dei coefficienti, un limite più stretto della somma. O ancora più stretto, per il valore assoluto dell '"ultimo" coefficiente diverso da zero - cioè il coefficiente della più piccola potenza di x che ha un coefficiente diverso da zero. (Probabilmente non aiuta a salvare alcun byte, solo una prova alternativa poiché RRT è probabilmente più familiare di Rouche per la maggior parte delle persone.) :)
Mathmandan,

1
@mathmandan l'approccio è più lungo di tre byte: provalo qui , anche se sono sicuro di aver perso uno o due trucchi
Giuseppe

@Giuseppe Grazie ad entrambi. Forse X>t_w&:GyZQ~), ma ancora 13 byte
Luis Mendo il

1
... ma ho trovato un'alternativa più breve per la gamma
Luis Mendo,

5

buccia , 10 9 byte

-1 byte grazie a Zgarb

uSȯf¬`Bṁṡ

Provalo online!

Spiegazione

       ṁṡ   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

Si potrebbe fare ṁṡinvece di oṡ►adeduplicare in seguito.
Zgarb,

@Zgarb Molto bello! Grazie
H.Piz,

5

Haskell , 54 byte

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

Provalo online!

Forza bruta e divisione sintetica.

Ungolfed con UniHaskell e-XUnicodeSyntax

import UniHaskell

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

Soluzione alternativa, 44 byte

Ringraziamo nimi.

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

Buona fortuna provandolo online , in quanto controlla tutti i numeri in un Intintervallo.


È possibile scorrere isopra [minBound..]e rilasciare l'intera tcosa. Chiama fcon Intelenchi espliciti , ad es f [1::Int,5,6]. Naturalmente questo non finisce in tempi ragionevoli.
nimi,

@nimi Perché mai smetterebbe? Non sarebbe loop infinito?
totalmente umano il

No, i Boundedtipi si fermano a maxBound, ad es print [minBound::Bool ..].
nimi,

4

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

-2 byte grazie agli ovs
grazie Luis Mendo per i limiti superiore / inferiore delle radici
-10 byte grazie a Mr. Xcoder

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

Provalo online!



@LuisMendo sì.
Rod

3
Il nostro attuale consenso sembra essere che i programmi devono sempre terminare, a meno che la sfida non indichi diversamente.
Zgarb,

@Zgarb lì, riparato!
Rod

Usando si numpy.polyvalrisparmia un bel po 'di byte
Mr. Xcoder

4

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

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

Provalo online!

Aggiornamento: usando il fatto di Luis Mendo, è uscito un altro 3 byte

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

Diventando più sciatti con i limiti, possiamo ridurre questi 5 byte in più per @Non il suggerimento di un albero:

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

Dopo aver pubblicato questo, OP ha commentato che consente "polinomi nativi", quindi ecco una soluzione da 25 byte che accetta il polinomio come input. Ciò funziona perché, per impostazione predefinita, Mathematica tiene conto dei polinomi sugli interi e tutte le radici razionali si presentano in una forma del genere m*x+bche non corrisponde alla corrispondenza del modello.

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

Come ha sottolineato @alephalpha, ciò fallirà nel caso in cui zero sia una radice, quindi per risolvere il problema possiamo usare il Optionalsimbolo:

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

Questo analizza bene Mathematica 11.0.1 ma fallisce e richiede un ulteriore set di parentesi b_:0nella versione 11.2. Questo richiede fino a 27 byte, più altri due dopo la versione 11.0.1. Sembra un "fix" è stato messo in qui

Provalo online!


1
Penso che puoi usare #.#invece di Tr@Abs@#: è un limite peggiore ma meno byte.
Non un albero il

1
OP ha detto in un commento che potresti usare il tipo polinomiale nativo della tua lingua se ne esiste uno. Non conosco bene Mathematica ma immagino che ce ne sia uno ... Ciò salverebbe i byte?
No, non ho mostrato il mio vero nome il


1
@alephalpha, risolto.
Kelly Lowder,


3

Wolfram Language (Mathematica) , 33 26 31 byte

Risolto un errore rilevato da Kelly Lowder nei commenti.

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

Provalo online!

Precedenti soluzioni errate:

Ho appena notato che per nessuna soluzione intera, l'output è indefinito anziché vuoto; che consente di rimuovere alcuni byte.

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

Provalo online!

Ora se non esiste una soluzione intera, la funzione ritorna x.

In precedenza:

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

Provalo online!


Ciò fallisce come attualmente indicato con 1,2,1 poiché ripete la radice e l'OP ha affermato che dovevano essere distinti. Devi Unionsistemarlo.
Kelly Lowder,

@KellyLowder: Ah, l'ho perso. Ma poi, mancava anche nei casi di test indicati.
Celtschk,

@KellyLowder: ora l'ho risolto. Nel caso in cui hai effettuato il downgrade per questo motivo, puoi per favore ripristinarlo?
Celtschk,

@cellschk, sì fatto.
Kelly Lowder

29 byte utilizzando una funzione non documentata di Solve: l'elenco delle variabili può essere omesso.
Roman

3

R , 61 59 byte

Un ringraziamento speciale a @mathmandan per aver sottolineato il mio approccio (errato) potrebbe essere salvato e giocato a golf!

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

Provalo online!

Prende input come un elenco di coefficienti in ordine crescente , ovvero c(-1,0,1)rappresenta -1+0x+1x^2.

Utilizzando il teorema della radice razionale, il seguente approccio funziona quasi per 47 byte:

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

Provalo online!

-p:pgenera un intervallo simmetrico (con un avviso) utilizzando solo il primo elemento p, a_0. Secondo il teorema della radice razionale , tutte le radici razionali di Pdevono essere della forma in p/qcui si pdivide a_0e qdivide a_n(più o meno). Quindi, usare just a_0è sufficiente per|a_0|>0 , come per qualsiasi q, |p/q|<=a_0. Tuttavia, quando a_0==0, come allora qualsiasi numero intero si divide 0, e quindi questo non riesce.

Tuttavia, Mathmandan sottolinea che davvero, in questo caso, ciò significa che esiste un fattore costante x^kche può essere preso in considerazione e, supponendo che ksia massimo, vediamo che

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

Quindi applichiamo il teorema della radice razionale Q(x)e, come a_kè garantito, essere diverso da zero dalla massima dik , a_kfornisce un limite ordinato per le radici intere di Q, e le radici di Psono le radici di Qinsieme a zero, quindi avremo tutti i numeri interi radici diP dell'applicazione di questo metodo.

Ciò equivale a trovare il primo coefficiente diverso da zero del polinomio, t=p[!!p][1] e usarlo al posto dell'ingenuo p[1]come limiti. Inoltre, poiché l'intervallo -t:tcontiene sempre zero, si applicaP a questo intervallo ci darebbe comunque zero come radice, se davvero lo è.

ungolfed:

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
}


(Penso che potresti usare i maxvalori assoluti invece di sum; questo non cambierebbe il conteggio dei byte, ma dovrebbe migliorare le prestazioni.) Comunque, sì, peccato che la versione più corta non funzioni a_0==0. Esiste un modo breve in R per cercare il primo coefficiente diverso da zero (con poteri crescenti) e usarlo invece? Ciò equivarrebbe a fattorizzare prima quante più x possibili (ovviamente, quindi dovresti ricordarti di produrre 0anche, che presumibilmente costerebbe alcuni byte.)
Mathmandan,

@mathmandan maxsarebbe più efficiente, ma al tuo secondo punto, poiché non devo preoccuparmi di emettere 0poiché è generato dall'intervallo -t:t(dove tè il primo coefficiente diverso da zero), risparmia 2 byte!
Giuseppe,

Oh, molto carino! (E anche una bella spiegazione.)
Mathmandan,

2

Gelatina , 8 byte

ASŒRḅ@Ðḟ

Provalo online! o come una suite di test!

Come?

ASŒRḅ @ Ðḟ || Programma completo (collegamento monadico).

AS || Somma i valori assoluti.
  ŒR || E crea l'intervallo simmetrico inclusivo dal suo valore negativo.
       Ðḟ || E scarta quelli che danno un valore veritiero ...
     ḅ @ || Quando li si collega al polinomio (utilizza la conversione di base).

Basato sulla risposta di Luis . Un'alternativa .


C'è qualcosa che mi manca nel prendere l'ordine (permesso) inverso e fare Ær+.Ḟ?
Jonathan Allan,

Sono un po 'confuso dal momento che la risposta di Python con Numpy non lo sta facendo neanche, e sto pensando di aver perso un caso limite.
Jonathan Allan,

@JonathanAllan Come mi aspettavo, il tuo fallisce [1,2,3].
Mr. Xcoder

"Se non esiste una soluzione per l'equazione data, l'output non è definito"
Jonathan Allan,

@JonathanAllan Ma non sicuro per [10,-42,8], giusto?
Mr. Xcoder

2

Ottava , 59 49 byte

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

Provalo online!

Questo è un porto della mia risposta R . L'unica differenza è che devo usare esplicitamente sign(t)e endgenerare l'intervallo e che deve polyvalcalcolare il polinomio.

Accetta l'input come vettore di riga di coefficienti in ordine decrescente.



2

C (gcc) , 127 126 123 byte

  • Salvato un byte grazie a Kevin Cruijssen ; giocare l+~j++a golf a l-++j.
  • Grazie a ceilingcat per il salvataggio di tre byte.
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;}

Provalo online!


Spiegazione

C (gcc) , 517 byte

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

Provalo online!


l+~j++può essere giocato a golfl-++j
Kevin Cruijssen il

@KevinCruijssen Grazie mille.
Jonathan Frech,

@ceilingcat Grazie.
Jonathan Frech,

1

Java 8, 141 140 byte

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

Ispirato da @Rod Python 2 (la sua versione da 82 byte) .

Sfida divertente! Ho sicuramente imparato molto quando investigavo sui polinomi e vedevo come alcuni altri qui lo hanno fatto.

Spiegazione:

Provalo online.

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 byte

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

Accetta i coefficienti in ordine decrescente di potenza e produce risultati in ordine decrescente.



Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.