Python: Finding multiple roots of nonlinear equation

前端 未结 3 1398
死守一世寂寞
死守一世寂寞 2020-12-03 05:38

Assume the following function:

f(x) = x * cos(x-4)

With x = [-2.5, 2.5] this function crosses 0 at f(0) = 0

相关标签:
3条回答
  • 2020-12-03 05:53

    In general (i.e. unless your function belongs to some specific class) you can't find all the global solutions - these methods usually do local optimization from given starting points.

    However, you can switch math.cos() with numpy.cos() and that will vectorize your function so it can solve for many values at once, e.g. fsolve(func, np.arange(-10,10,0.5)).

    0 讨论(0)
  • 2020-12-03 05:59

    Define your function so that it can take either a scalar or a numpy array as an argument:

    >>> import numpy as np
    >>> f = lambda x : x * np.cos(x-4)
    

    Then pass a vector of arguments to fsolve.

    >>> x = np.array([0.0, -0.75])
    >>> fsolve(f,x)
    array([ 0.        , -0.71238898])
    
    0 讨论(0)
  • 2020-12-03 06:03

    I once wrote a module for this task. It's based on chapter 4.3 from the book Numerical Methods in Engineering with Python by Jaan Kiusalaas:

    import math
    
    def rootsearch(f,a,b,dx):
        x1 = a; f1 = f(a)
        x2 = a + dx; f2 = f(x2)
        while f1*f2 > 0.0:
            if x1 >= b:
                return None,None
            x1 = x2; f1 = f2
            x2 = x1 + dx; f2 = f(x2)
        return x1,x2
    
    def bisect(f,x1,x2,switch=0,epsilon=1.0e-9):
        f1 = f(x1)
        if f1 == 0.0:
            return x1
        f2 = f(x2)
        if f2 == 0.0:
            return x2
        if f1*f2 > 0.0:
            print('Root is not bracketed')
            return None
        n = int(math.ceil(math.log(abs(x2 - x1)/epsilon)/math.log(2.0)))
        for i in range(n):
            x3 = 0.5*(x1 + x2); f3 = f(x3)
            if (switch == 1) and (abs(f3) >abs(f1)) and (abs(f3) > abs(f2)):
                return None
            if f3 == 0.0:
                return x3
            if f2*f3 < 0.0:
                x1 = x3
                f1 = f3
            else:
                x2 =x3
                f2 = f3
        return (x1 + x2)/2.0
    
    def roots(f, a, b, eps=1e-6):
        print ('The roots on the interval [%f, %f] are:' % (a,b))
        while 1:
            x1,x2 = rootsearch(f,a,b,eps)
            if x1 != None:
                a = x2
                root = bisect(f,x1,x2,1)
                if root != None:
                    pass
                    print (round(root,-int(math.log(eps, 10))))
            else:
                print ('\nDone')
                break
    
    f=lambda x:x*math.cos(x-4)
    roots(f, -3, 3)
    

    roots finds all roots of f in the interval [a, b].

    0 讨论(0)
提交回复
热议问题