查找多项式的积分根


19

挑战

面临的挑战是编写一个程序,该程序将任何n次多项式方程式的系数作为输入,并返回方程式成立的x 的积分值。这些系数将按照功率减小或增大的顺序作为输入提供。您可以假定所有系数都是整数

输入输出

输入将是功率递减顺序的等式系数。方程的度数(即x的最大乘方)始终比输入中元素总数的总和小1。

例如:

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

您的输出应仅是满足给定方程的x 的不同积分值。所有输入系数都是整数,并且输入多项式将不是零多项式。如果给定方程式无解,则输出不确定。

如果方程式具有重复的根,则仅显示该特定根一次。您可以按任何顺序输出值。另外,假设输入将至少包含2个数字。

例子

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

请注意,第二个示例中的方程式的根也为0.2,但不会显示为0.2,因为它不是整数。

计分

这是,因此最短的代码(以字节为单位)获胜!


7
注:投票结束之前,请考虑,这个问题是不是一个重复这一个。我可以想到至少一个解决该问题的方法,该方法对于其他挑战将无法轻易修改(尽管我没有在说什么;这留给了您; P)。
暴民埃里克(Erik the Outgolfer)

我们可以假设我们只需要返回语言整数范围内的根吗?或者即使增加了语言整数类型范围,该算法也应该起作用,但是行为保持不变。
Οurous

1
如果您的语言支持,我们还可以使用本机多项式类型吗?
瑕疵的

1
如果没有解决方案,程序是否会永远运行?
杰克M

1
这是为了使事情简单。
Manish Kundu

Answers:


6

MATL13 12字节

|stE:-GyZQ~)

在线尝试!

这利用了这样的事实:对于整数系数,任何根的绝对值都严格小于系数的绝对值之和。

说明

以输入[1 5 6]为例。

|    % 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
作为Rouche定理的替代方法,Rational Roots定理也足以证明您使用的界限是正确的。根据有理根定理,所有整数根的绝对值都由系数的绝对值的最大值来界定,该界限比总和更紧密。甚至更严格地讲,用“最后一个”非零系数的绝对值表示,即具有非零系数的x的最小幂的系数。(可能无助于保存任何字节,只是另一种证明,因为RRT在大多数人看来比Rouche更熟悉。):)
mathmandan

1
@mathmandan该方法要再长三个字节:在这里尝试,尽管我确定我错过了一两个窍门
朱塞佩

@Giuseppe都感谢。也许X>t_w&:GyZQ~),但仍有13个字节
路易斯Mendo

1
...但我发现的范围更短的替代
路易斯Mendo

5

外壳10 9字节

-1字节感谢Zgarb

uSȯf¬`Bṁṡ

在线尝试!

说明

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

您可以ṁṡ代替oṡ►a以后进行重复数据删除。
Zgarb

@Zgarb非常好!谢谢
H.PWiz

5

Haskell,54个字节

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

在线尝试!

蛮力和合成师。

UniHaskell-XUnicodeSyntax

import UniHaskell

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

替代解决方案,44字节

归功于nimi。

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

您在线试试运气,因为它可以检查范围内的每个数字Int


可以遍历i[minBound..]拖放整个t事情。f使用显式Int列表进行调用,例如f [1::Int,5,6]。当然,这不会在合理的时间内完成。
nimi

@nimi为什么会停止?它不会无限循环吗?
–totalhuman

不,Bounded类型停在maxBound,例如print [minBound::Bool ..]
nimi

4

Python 2 + numpy,95 93 91 103 93 91 82字节

感谢ovs -2个字节感谢
Luis Mendo 的根的上下边界
-10个字节,感谢Xcoder先生

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

在线尝试!



@LuisMendo是的。
Rod

3
我们当前的共识似乎是程序必须始终终止,除非挑战另有说明。
Zgarb

@Zgarb在那里,固定!
Rod

使用会numpy.polyval节省很多字节
Xcoder先生,18年

4

Wolfram语言(Mathematica)50 47 42 25 27字节

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

在线尝试!

更新:利用路易斯·门多的事实,打另外3个字节

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

随着边界变得更加草率,我们可以每@Not减少这5个字节不是树的建议:

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

发布此内容后,OP注释允许使用“本机多项式”,因此这是一个25字节的解决方案,接受多项式作为输入。之所以可行,是因为默认情况下Mathematica会在整数上分解多项式,并且任何有理根都以这种形式出现m*x+b,即模式匹配失败。

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

正如@alephalpha指出的那样,对于以零为根的情况,这将失败,因此要修复此问题,我们可以使用Optional符号:

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

这可以解析良好的Mathematica 11.0.1,但失败了,并且b_:0在版本11.2中需要附加括号。这将占用最多27个字节,在11.0.1版之后又增加了两个字节。好像在这里放了一个“修复”

在线尝试!


1
我认为您可以使用#.#代替Tr@Abs@#:这是一个较差的约束,但字节数较少。
不是一棵树

1
OP在一条评论中说,如果存在,您可以使用语言的本机多项式类型。我不太了解Mathematica,但我想有一个……可以节省字节吗?
不,没有显示我的真实姓名,


1
@alephalpha,已修复。
凯莉·洛德


3

Wolfram语言(Mathematica)33 26 31字节

修复了Kelly Lowder在评论中指出的错误。

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

在线尝试!

先前的错误解决方案:

我只是注意到,对于没有整数解的情况,输出是不确定的,而不是空列表。允许删除一些字节。

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

在线尝试!

现在,如果不存在整数解,函数将返回x

先前:

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

在线尝试!


如当前用1,2,1所述,此操作失败,因为它重复了根,并且OP表示必须区分。您需要 Union解决此问题。
凯利·洛德

@KellyLowder:啊,我错过了。但是,在给定的测试用例中也缺少它。
celtschk

@KellyLowder:我现在修复了它。万一您因为这个原因投票失败,可以请您还原吗?
celtschk

@cellschk,是的。
凯利·洛德

通过使用未记录的29个字节的功能Solve:可以省略变量列表。
罗马

3

R61 59字节

特别感谢@mathmandan指出我的(错误的)方法可以保存并打高尔夫球!

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

在线尝试!

递增的顺序将输入作为系数列表,即c(-1,0,1)表示-1+0x+1x^2

使用有理根定理,以下方法几乎可以正常工作,占用47个字节:

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

在线尝试!

-p:p仅使用的第一元件产生的对称范围(带有警告)pa_0。通过有理根定理,所有理性的根P必须是这样的形式p/q,其中p分歧a_0q分裂a_n(正或负)。因此,对于任何,使用just a_0就足够了。然而,当,如再|a_0|>0q|p/q|<=a_0a_0==0整数都将除0,从而失败。

但是,mathmandan指出,实际上,在这种情况下,这意味着可以将其中的一个常数因子x^k排除在外,并且假设k最大,我们看到

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

然后,我们应用有理根定理Q(x),并且如a_k保证通过的极大性为非零ka_k提供开往的整数根一整齐Q,和根P是根Q连同零,所以我们将所有的整数P通过应用此方法的根源。

这等效于找到多项式的第一个非零系数,t=p[!!p][1]然后使用它而不是朴素p[1]作为界限。此外,由于范围-t:t始终包含零,因此应用P因此即使于该范围,仍将以零为根。

松散:

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
}


(我认为您可以使用的max绝对值代替sum;不会改变字节数,但是应该可以提高性能。)无论如何,是的,遗憾的是较短的版本不适用于a_0==0。R中是否有一些简短的方法来搜索第一个(幂次上升的)非零系数,并使用它呢?这将对应于首先排除尽可能多的x(当然,然后您还必须记住也要输出0,这大概会花费一些字节。)
mathmandan

@mathmandan max会更高效,但是到您的第二点,0由于它是由范围-t:t(其中t第一个非零系数)生成的,因此我不必担心输出,它节省了2个字节!
朱塞佩

嗯,很不错!(还有一个很好的解释。)
mathmandan '18

2

果冻,8 字节

ASŒRḅ@Ðḟ

在线尝试!作为测试套件!

怎么样?

ASŒRḅ@Ðḟ|| 完整程序(单声道链接)。

AS || 求和绝对值。
  ŒR|| 并从其负值创建对称的包含范围。
       Ðḟ|| 并丢弃那些产生真实价值的东西...
     ḅ@ || 将它们插入多项式时(使用基数转换)。

根据路易斯的回答另一种选择


采取(允许的)反向顺序并执行操作时,我缺少什么Ær+.Ḟ吗?
乔纳森·艾伦

我有点困惑,因为使用numpy的Python答案也没有这样做,并且我想我错过了一些边缘情况。
乔纳森·艾伦

@JonathanAllan如我所料,您的失败[1,2,3]
Xcoder先生18年

“如果给定方程没有解,则输出不确定”
Jonathan Allan

@JonathanAllan但是它确实失败[10,-42,8],对吧?
Xcoder先生18年

2

八度59 49字节

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

在线尝试!

这是我的R回答的一部分。唯一的区别是我必须显式使用sign(t)end生成范围,并且polyval必须计算多项式。

以降序将输入作为系数的行向量。



2

C(GCC) 127个 126 123字节

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

在线尝试!


说明

C(gcc),517字节

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

在线尝试!


l+~j++可以打高尔夫球l-++j
凯文·克鲁伊森

@KevinCruijssen非常感谢。
乔纳森·弗雷希

@ceilingcat谢谢。
乔纳森·弗雷奇

1

爪哇8,141 140个字节

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

受到@Rod的Python 2答案(他的82字节版本)的启发。

有趣的挑战!在研究多项式并了解其他人如何做到这一点时,我当然学到了很多。

说明:

在线尝试。

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个字节

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

以幂的降序取系数,并以降序输出结果。



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.