简体   繁体   English

在R中找到两个根之间的距离

[英]To find the distance between two roots in R

Suppose I have a function f(x) that is well defined on an interval I. I want to find the greatest and smallest roots of f(x), then taking the difference of them. 假设我有一个在间隔I上定义好的函数f(x)。我想找到f(x)的最大和最小根,然后取它们的差。 What is a good way to program it? 有什么好的编程方法?

To be precise, f can at worst be a rational function like (1+x)/(1-x). 确切地说,f在最坏的情况下可能是一个有理函数,如(1 + x)/(1-x)。 It should be a (high degree) polynomial most of the times. 大多数时候,它应该是(高次)多项式。 I only need to know the result numerically to some precision. 我只需要在某种程度上精确地知道结果。

I am thinking about the following: 我在考虑以下方面:

  1. Convert f(x) into a form recognizable by R. (I can do) 将f(x)转换为R可以识别的形式。(我可以)

  2. Use R to list all roots of f(x) on I (I found the uniroot function only give me one root) 使用R列出I上f(x)的所有根(我发现uniroot函数仅给我一个根)

  3. Use R to to find the maximum and minimum elements in the list (should be possible once I converted it to a vector) 使用R查找列表中的最大和最小元素(将其转换为向量后应该可以)

  4. Taking the difference of the two roots. 取二根之差。 (should be trivial) (应该是微不足道的)

I am stuck on step (2) and I do not know what to do. 我被困在步骤(2)上,我不知道该怎么办。 My professor give a brutal force solution, suggesting me to do: 我的教授给出了一种残酷的解决方案,建议我这样做:

  1. Divide interval I into one million pieces. 将间隔I分为一百万个。

  2. Evaluate f on each end points, find the end points where f>=0. 在每个端点上评估f,找到f> = 0的端点。

  3. Choose the maximum and minimum elements from the set formed in step 2. 从步骤2中形成的集合中选择最大和最小元素。

  4. Take the difference between them. 拿他们之间的区别。

I feel this way is not very efficient and might not work for all f in general, but I am having trouble to implement it even for quadratics. 我觉得这种方法效率不高,一般来说可能不适用于所有f,但是即使对于二次运算,我也难以实现。 I do not know how to do step (2) as well. 我也不知道如何执行步骤(2)。 So I want to ask for a hint or some toy examples. 所以我想问一个提示或一些玩具的例子。


At this point I am trying to implement the following code: 此时,我正在尝试实现以下代码:

Y=rep(0,200)
dim(Y)=c(100,2)
for(i in 1:100){
X=rnorm(9,0,1)
Z=rnorm(16,0,1)
a=0.64
b=a*sum(Z^2)/sum(X^2)
root_intervals <- function(f, interval, n = 1e6) {
    xvals <- seq(interval[1], interval[2], length = n)
    yvals <- f(xvals)
    ypos <- yvals > 0
    x1 <- which(tail(ypos, -1) != head(ypos, -1))
    x2 <- x1 + 1
    ## so all the zeroes we can see are between x1 and x2
    return(cbind(xvals[x1], xvals[x2]))
}

at here everything is okay, but when I try to extract the roots to Y[i,1], Y[i,2] by 在这里一切正常,但是当我尝试通过以下方式将根提取到Y [i,1],Y [i,2]时:

Y[i,1]=(ri<-root intervals(function(x)(x/(a*x+b))^{9/2}*(1/((1-a)+a*(1-a)/b*x))^4-0.235505, c(0,40),n=1e6)[1]

I found I cannot evaluate it anymore. 我发现我无法对其进行评估。 R keep telling me R不断告诉我

Error: unexpected symbol in:
"}
Y[i,1]=(ri<-root intervals"

and I got stuck. 我被卡住了。 I really appreciate everyone's help as I am feeling lost. 当我感到迷茫时,我非常感谢大家的帮助。

I checked the function's expression many times using the plot function and it has no grammar mistakes. 我使用plot函数多次检查了函数的表达式,并且没有语法错误。 Also I believe it is well defined for all X in the interval. 我也相信间隔中所有X的定义都很好。

This should give you a good start on the brute force solution. 这应该为您提供蛮力解决方案的良好开端。 You're right, it's not elegant, but for relatively simple univariate functions, evaluating 1 million points is trivial. 没错,这并不优雅,但是对于相对简单的单变量函数而言,评估一百万点是微不足道的。

root_intervals <- function(f, interval, n = 1e6) {
    xvals <- seq(interval[1], interval[2], length = n)
    yvals <- f(xvals)
    ypos <- yvals > 0
    x1 <- which(ypos[-1] != head(ypos, -1))
    x2 <- x1 + 1
    ## so all the zeroes we can see are between x1 and x2
    return(cbind(xvals[x1], xvals[x2]))
}

This function returns a two column matrix of x values, where the function changes sign between column 1 and column 2: 此函数返回x值的两列矩阵,其中该函数在第1列和第2列之间更改符号:

f1 <- function (x) 0.05 * x^5 - 2 * x^4 + x^3 - x^2 + 1

> (ri <- root_intervals(f1, c(-10, 10), n = 1e6))
           [,1]       [,2]
[1,] -0.6372706 -0.6372506
[2,]  0.8182708  0.8182908

> f1(ri)
              [,1]          [,2]
[1,] -3.045326e-05  6.163467e-05
[2,]  2.218895e-05 -5.579081e-05

Wolfram Alpha confirms results on the specified interval. Wolfram Alpha按指定的时间间隔确认结果。

The top and bottom rows will be the min and max intervals found. 顶部和底部将是找到的最小和最大间隔。 These intervals (over which the function changes sign) are precisely what uniroot wants for it's interval , so you could use it to solve for the (more) exact roots. 这些间隔(函数改变符号的interval )正是uniroot想要的interval ,因此您可以使用它来求解(更多)确切的根。 Of course, if the function changes sign twice within one interval (or any even number of times), it won't be picked up, so choose a big n ! 当然,如果函数在一个时间间隔(或任何偶数次)内两次更改符号,它将不会被拾取,因此请选择大n

Response to edited question: 对已编辑问题的答复:

Looks like your trying to define a bunch of functions, but your edits have syntax errors. 看起来您试图定义一堆函数,但是您的编辑存在语法错误。 Here's what I think you're trying to do: (this first part might take some more work to work right) 这是我认为您要尝试执行的操作:(第一部分可能需要更多工作才能正常工作)

my_funs <- list()
Y=rep(0,200)
dim(Y)=c(100,2)
for(i in 1:100){
  X=rnorm(9,0,1)
  Z=rnorm(16,0,1)
  a=0.64
  b=a*sum(Z^2)/sum(X^2)
  my_funs[[i]] <- function(x){(x/(a*x+b))^{9/2}*(1/((1-a)+a*(1-a)/b*x))^4-0.235505}
}

Here's using the root_intervals on the first of your generated functions. 这是在您生成的第一个函数上使用root_intervals。

> root_intervals(my_funs[[1]], interval = c(0, 40))
           [,1]       [,2]
[1,]  0.8581609  0.8582009
[2,] 11.4401314 11.4401714

Notice the output, a matrix , with the roots of the function being between the first and second columns. 注意输出矩阵 ,函数的根在第一和第二列之间。 Being a matrix, you can't assign it to a vector. 作为矩阵,您不能将其分配给向量。 If you want a single root, use uniroot using each row to set the upper and lower bounds. 如果要使用单个根, uniroot每行中使用uniroot设置上限和下限。 This is left as an exercise to the reader. 这留给读者练习。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM