找到一个复杂多项式的根

计算科学 多项式
2021-12-09 20:54:04

对于多项式

p(x)=(x1)(x2)(x20)223x19,

我尝试fzero()在 MATLAB 中使用,并将间隔设置为[0.5,1.5][19.5,20.5]. 它确实为[0.5,1.5]大概[7.5,8.5]. 但是,由于符号的原因,当它处理更大的数字时,它似乎不起作用。

有谁知道如何解决这个问题?还是其他一些方法?

1个回答

一种技术是使用具有任意大整数的库并使用定点算法。只需将 x 放大某个整数因子,然后以定点计算您的多项式,只保留符号。

从您知道正数和负数的两个值中,您可以执行二分搜索。最后,除以固定点因子并得到您正在寻找的值。

以下内容仍在进行中,但应该会给您正确的想法。(使用 vanilla python,因为它支持大整数)

它找到以下根。它尚未经过彻底调试,但希望这能让您了解一种方法。

1.0
2.0
2.999999999999805
4.000000000261023
4.999999927551538
6.000006943952296
6.999697233936014
8.007267603450376
8.917250248517071
20.846908101482256

寻找复杂的根源留给读者作为练习:-)

# an arbitrary fixed-point precision factor
factor = 2 ** 80

def poly(x):
    # this function computes 2^23*(x−1)(x−2)...(x−20) − x^19
    # it has the same sign as (x−1)(x−2)...(x−20) − x^19 / 2^23

    pos = 1
    for i in range(20):
        pos = pos * (x - (i + 1) * factor)
    pos = (2 ** 23) * pos
    # pos is (2 ** 23) * (x−1)(x−2)...(x−20) (factor^20)

    neg = (x ** 19) * factor
    # neg is x^19 (factor^19) (factor)

    #print(pos,neg)

    ret = pos - neg 
    # ret is now 2^23*(x−1)(x−2)...(x−20) (factor^20) - x^19 (factor^19) (factor)
    # which is 2^23*(x−1)(x−2)...(x−20) (factor^20) - x^19 (factor^20)
    # which is (factor^20)( 2^23*(x−1)(x−2)...(x−20) - x^19)
    # which has the same sign as (2^23*(x−1)(x−2)...(x−20) - x^19)

    return ret

def search(x,y):

    # print("Searching between {} and {}".format(x/factor,y/factor))
    while((y - x) > 1):
        z = (x + y) // 2

        if (poly(z) < 0) == (poly(x) < 0):
            x = z
        else:
            y = z

    print(y / factor) # here, we go back to floating point and incur loss of precision


def main():

    poly(2 * factor)

    last_v = None
    last_sign = None

    steps = 100000 # number of steps
    lower = -10   # range from
    upper = 30    # range to

    for i in range(steps):
        v = (((steps - i) * lower) + (i * upper)) * factor // steps

        sign = poly(v) > 0

        if (last_sign is not None) and (sign != last_sign):
            search(last_v,v)

        last_v = v
        last_sign = sign

main()