欢迎光临
我们一直在努力

R语言二分法求函数根

核心思想

如果函数f(x)[a,b]上连续,并且满足:

f(a)f(b)<0

那么说明f(a) 和f(b)异号。根据连续函数的零点存在定理,区间(a,b)内至少存在一个根:

\\exists x^*\\in(a,b),\\quad f(x^*)=0

理论刨析

      定初始区间

以函数为f(x)=x^2+2x-15为例 。

我们取初始区间为[1,6],二分法要求函数在区间两端异号,即:

f(a)f(b)<0

现在取:

a=1,\\qquad b=6

计算左端点函数值:

f(1)=1^2+2\\times1-15=-12

计算右端点函数值:

f(6)=6^2+2\\times6-15=33

因此:

f(1)f(6)=(-12)\\times33=-396<0

所以,区间[1,6]满足二分法的使用条件,说明该区间内至少存在一个根:

x^*\\in(1,6)

二分法

第一次二分

初始区间为:

[a_0,b_0]=[1,6]

中点为:

c_0=\\frac{a_0+b_0}{2}=\\frac{1+6}{2}=3.5

计算中点函数值:

f(3.5)=3.5^2+2\\times3.5-15=4.25

因为:

f(1)<0,\\qquad f(3.5)>0

所以:

f(1)f(3.5)<0

因此根位于左半区间:

[a_1,b_1]=[1,3.5]

第二次二分

当前区间为:

[a_1,b_1]=[1,3.5]

中点为:

c_1=\\frac{1+3.5}{2}=2.25

计算函数值:

f(2.25)=2.25^2+2\\times2.25-15=-5.4375

因为:

f(2.25)<0,\\qquad f(3.5)>0

所以:

f(2.25)f(3.5)<0

因此根位于右半区间:

[a_2,b_2]=[2.25,3.5]

第三次二分

当前区间为:

[a_2,b_2]=[2.25,3.5]

中点为:

c_2=\\frac{2.25+3.5}{2}=2.875

计算函数值:

f(2.875)=2.875^2+2\\times2.875-15=-0.984375

因为:

f(2.875)<0,\\qquad f(3.5)>0

所以根位于右半区间:

[a_3,b_3]=[2.875,3.5]

当我们不断迭代的时候,区间[a,b]会不断收敛到真实值附近。但是我们不可能无限迭代。

终止条件

1.函数值足够接近 0

当中点c_k的函数值已经非常接近 0 时,可以停止:

|f(c_k)|<\\varepsilon

其中\\varepsilon是我们设定的误差精度,例如:

\\varepsilon=10^{-6}

也就是说,只要:

|c_k^2+2c_k-15|<10^{-6}

就认为当前中点c_k已经可以作为方程的近似根。

2. 区间长度足够小

二分法每次都会把区间缩小一半。当区间已经非常短时,说明根已经被锁定在一个很小的范围内,此时也可以停止。

停止条件可以写为:

\\frac{b_k-a_k}{2}<\\varepsilon

这里的含义是:当前中点c_k与真实根x^*的最大误差已经小于\\varepsilon

因为:

c_k=\\frac{a_k+b_k}{2}

所以有:

|c_k-x^*|\\leq \\frac{b_k-a_k}{2}

因此,只要:

\\frac{b_k-a_k}{2}<\\varepsilon

就可以保证近似根的误差小于设定精度。

3. 达到最大迭代次数

为了防止程序出现异常循环,实际编程时通常还会设置最大迭代次数:

k\\geq k_{\\max}

例如:

k_{\\max}=100

如果循环次数达到 100 次,即使还没有满足精度条件,也强制停止。

二分法就是利用连续函数的变号性质,通过“取中点—判符号—缩区间”的方式逐步逼近方程的根。

案例实操

一、for循环版本

结束条件是:达到最大迭代次数。

# ============================================================
# 二分法求根:for 循环版本
# 结束条件:达到最大迭代次数
# 方程:f(x) = x^2 + 2x – 15
# 初始区间:[1, 6]
# ============================================================

# 1. 定义目标函数
f <- function(x) {
return(x^2 + 2 * x – 15)
}

# 2. 设置初始区间
a <- 1
b <- 6

# 3. 检查初始区间是否满足二分法条件
if (f(a) * f(b) > 0) {
stop("初始区间两端函数值同号,不能使用二分法。")
}

# 4. 设置最大迭代次数
max_iter <- 30

# 5. 创建结果保存表
result_for <- data.frame(
iteration = integer(),
a = numeric(),
b = numeric(),
c = numeric(),
f_c = numeric()
)

# 6. for 循环进行二分迭代
for (k in 1:max_iter) {

# 计算中点
c <- (a + b) / 2

# 计算中点函数值
f_c <- f(c)

# 保存当前迭代结果
result_for <- rbind(
result_for,
data.frame(
iteration = k,
a = a,
b = b,
c = c,
f_c = f_c
)
)

# 判断根所在区间
if (f(a) * f_c < 0) {
b <- c
} else {
a <- c
}
}

# 7. 输出迭代结果
print(result_for)

# 8. 输出最终近似根
root_for <- c

cat("for循环版本的近似根为:", root_for, "\\n")
cat("近似根处的函数值为:", f(root_for), "\\n")
cat("总迭代次数为:", max_iter, "\\n")

二、while循环版本

结束条件是:当中点函数值足够接近 0 时停止。

# ============================================================
# 二分法求根:while 循环版本
# 结束条件:函数值精度 |f(c)| < epsilon
# 方程:f(x) = x^2 + 2x – 15
# 初始区间:[1, 6]
# ============================================================

# 1. 定义目标函数
f <- function(x) {
return(x^2 + 2 * x – 15)
}

# 2. 设置初始区间
a <- 1
b <- 6

# 3. 检查初始区间是否满足二分法条件
if (f(a) * f(b) > 0) {
stop("初始区间两端函数值同号,不能使用二分法。")
}

# 4. 设置精度
epsilon <- 1e-6

# 5. 初始化变量
k <- 0
c <- (a + b) / 2
f_c <- f(c)

# 6. 创建结果保存表
result_while <- data.frame(
iteration = integer(),
a = numeric(),
b = numeric(),
c = numeric(),
f_c = numeric()
)

# 7. while 循环进行二分迭代
while (abs(f_c) >= epsilon) {

# 迭代次数加 1
k <- k + 1

# 保存当前迭代结果
result_while <- rbind(
result_while,
data.frame(
iteration = k,
a = a,
b = b,
c = c,
f_c = f_c
)
)

# 判断根所在区间
if (f(a) * f_c < 0) {
b <- c
} else {
a <- c
}

# 重新计算新区间中点
c <- (a + b) / 2

# 重新计算中点函数值
f_c <- f(c)
}

# 8. 保存最后一次满足精度的结果
result_while <- rbind(
result_while,
data.frame(
iteration = k + 1,
a = a,
b = b,
c = c,
f_c = f_c
)
)

# 9. 输出迭代结果
print(result_while)

# 10. 输出最终近似根
root_while <- c

cat("while循环版本的近似根为:", root_while, "\\n")
cat("近似根处的函数值为:", f(root_while), "\\n")
cat("总迭代次数为:", k + 1, "\\n")
cat("设定精度为:", epsilon, "\\n")

赞(0)
未经允许不得转载:171主机测评 » R语言二分法求函数根
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址