且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用 numpy(和 scipy)查找函数的所有零?

更新时间:2023-02-26 16:24:48

我看到的主要问题是你是否真的可以找到所有根——正如评论中已经提到的那样,这并不总是可能的.如果你确定你的函数不是完全病态的(sin(1/x) 已经提到过),下一个是你对丢失一个或几个根的容忍度.换句话说,它是关于你准备走多长时间以确保你没有错过任何一个——据我所知,没有通用的方法来为你隔离所有的根,所以你必须自己做.你展示的已经是合理的第一步.一些评论:

The main problem I see with this is if you can actually find all roots --- as have already been mentioned in comments, this is not always possible. If you are sure that your function is not completely pathological (sin(1/x) was already mentioned), the next one is what's your tolerance to missing a root or several of them. Put differently, it's about to what length you are prepared to go to make sure you did not miss any --- to the best of my knowledge, there is no general method to isolate all the roots for you, so you'll have to do it yourself. What you show is a reasonable first step already. A couple of comments:

  • Brent 的方法在这里确实是一个不错的选择.
  • 首先,处理分歧.由于在您的函数中分母中有 Bessels,您可以先求解 它们的根 - ***在例如 Abramovitch 和 Stegun (数学世界链接).这将比使用您正在使用的临时网格更好.
  • 你可以做什么,一旦你找到了两个根或分歧,x_1x_2,在区间 [x_1+epsilon> 中再次运行搜索, x_2-epsilon].继续直到找不到更多的根(布伦特的方法保证收敛到 a 根,前提是有一个).
  • 如果你不能列举所有的分歧,你可能需要在验证候选人确实是分歧的时候更加小心:给定 x 不要只检查 f(x) 很大,检查一下,例如|f(x-epsilon/2)|>|f(x-epsilon)| 用于 epsilon 的几个值(1e-8、1e-9、1e-10 之类的).
  • 如果你想确保你没有简单地接触零的根,寻找函数的极值,对于每个极值,x_e,检查 f 的值(x_e).
  • Brent's method is indeed a good choice here.
  • First of all, deal with the divergencies. Since in your function you have Bessels in the denominators, you can first solve for their roots -- better look them up in e.g., Abramovitch and Stegun (Mathworld link). This will be a better than using an ad hoc grid you're using.
  • What you can do, once you've found two roots or divergencies, x_1 and x_2, run the search again in the interval [x_1+epsilon, x_2-epsilon]. Continue until no more roots are found (Brent's method is guaranteed to converge to a root, provided there is one).
  • If you cannot enumerate all the divergencies, you might want to be a little more careful in verifying a candidate is indeed a divergency: given x don't just check that f(x) is large, check that, e.g. |f(x-epsilon/2)| > |f(x-epsilon)| for several values of epsilon (1e-8, 1e-9, 1e-10, something like that).
  • If you want to make sure you don't have roots which simply touch zero, look for the extrema of the function, and for each extremum, x_e, check the value of f(x_e).