Найти все корни уравнения между заданным диапазоном - PullRequest
1 голос
/ 04 ноября 2019

Я пытаюсь найти корень между диапазонами уравнения следующим образом:

def f(x):
  return np.tan(x) - 3*x

from scipy.optimize import fsolve

In [14]: fsolve(f,0)
Out[14]: array([ 0.]) # one of the root of the eqn

Но для любого другого начального предположения он дает 0, если исходное предположение не очень близко к корню.

In [15]: fsolve(f, 2)
Out[15]: array([ 0.])  # expected ouptut 1.32419445
In [16]: fsolve(f,[1.32])
Out[16]: array([ 1.32419445])

In [17]: fsolve(f, 5)
Out[17]: array([ 0.])  # expected ouptut 4.64068363
In [18]: fsolve(f,[4.64])
Out[18]: array([ 4.64068363])

Есть ли способ найти все корни между заданным диапазоном?

Ответы [ 2 ]

1 голос
/ 04 ноября 2019

Каждая функция, как кусок дерева, имеет свое «зерно», которое может создавать проблемы при работе с ним. Один из моих любимых методов - переставить выражение, чтобы избавиться от переменной в знаменателе. В вашем случае решение как sin(x)-3*x*cos(x) имеет гораздо лучшее поведение:

>>> [nsolve(sin(x)-3*x*cos(x),i).n(2) for i in range(10)]
[0, 1.3, 1.3, -1.3, 4.6, 4.6, 1.3, 7.8, 7.8, 7.8]

Продолжение также является полезным методом для плохо управляемых функций. В этом случае может быть полезно использовать параметр для медленного включения плохо функционирующей части функции. В вашем случае x в 3*x*cos(x) усложняет ситуацию. Но если вы поделите на приблизительное значение, которое вы ищете, и медленно измените этот делитель на 1, вы можете следовать приблизительному корню до желаемого корня. Вот пример:

>>> a = 0.
>>> for j in range(5):
...  for i in range(10):
...   a = nsolve(sin(x)-3*x*cos(x)/(a + i*(1-a)/9),a)
...  print(a)
...  a += pi.n()+0.1
...
0
4.64068363077555
7.81133447513087
10.9651844009289
14.1135533715145
0 голосов
/ 04 ноября 2019

Если вам подходит простой бинарный поиск и вы можете указать x, для которых f имеет разные знаки, может помочь следующее:

from math import *

eps = 1e-20

def test_func(x):
    return tan(x) - 3*x

def find_root(f, a, b):
    for i in range(20):
        x = i / 10.0
        print(x, f(x))
    fa = f(a)
    fb = f(b)
    if fa*fb > 0:
        raise ("f(a) and f(b) need to have different signs")
    while True:
        if fabs(fa) < eps:
            return a
        elif fabs(fb) < eps:
            return b
        else:
            m = (a + b) / 2
            fm = f(m)
            if m == a or m == b:
                return m
            if fa*fm > 0:
                a, fa = m, fm
            else:
                b, fb = m, fm

r = find_root(test_func, 1.0, 1.5)
print (r, test_func(r))  # 1.324194449575503 3.1086244689504383e-15
...