最优化 | 一维搜索与方程求根 | C++实现

news/2024/4/29 17:35:29/文章来源:https://blog.csdn.net/weixin_42301220/article/details/126816206

文章目录

  • 参考资料
  • 前言
  • 1. 二分法求根
    • 1.1 [a,b]区间二分法求根
      • 1.1.1 原理
      • 1.1.2 C++实现
    • 1.2 区间右侧无穷的二分法求根
    • 1.3 求含根区间
  • 2. 牛顿法求根
    • 2.1 原理
    • 2.2 c++实现
  • 3. 梯度下降法求根
    • 3.1 c++实现
  • 4. 一维搜索的区间
    • 4.1 一般一维搜索方法
    • 4.2 黄金分割法(0.618)
      • 4.2.1 原理
      • 4.2.2 c++实现
    • 4.3 抛物线法
      • 4.3.1 原理
      • 4.3.2 c++实现
      • 4.3.3 改进
      • 4.3.4 c++实现

参考资料

  • 一维搜索与求根
  • 牛顿法求极值
  • 黄金分割算法

前言

  • 即使目标函数 f(x)f(x)f(x) 是一元函数,求最小值点也经常需要使用数值迭代方法。

  • 在多元目标函数优化 中,一般每次迭代从上一步的 x(t)\boldsymbol{x}^{(t)}x(t) 先确定一个下降方向 d(t)\boldsymbol{d}^{(t)}d(t) ,然后对派生出的一元函数 h(α)=f(x(t)+αd(t)),α≥0h(\alpha)=f\left(\boldsymbol{x}^{(t)}+\alpha \boldsymbol{d}^{(t)}\right), \alpha \geq 0h(α)=f(x(t)+αd(t)),α0 求最小值点得到下降的步长 αt\alpha_tαt ,并令 x(t+1)=x(t)+αtd(t)\boldsymbol{x}^{(t+1)}=\boldsymbol{x}^{(t)}+\alpha_t \boldsymbol{d}^{(t)}x(t+1)=x(t)+αtd(t) , 求步长 的过程称为一维搜索,搜索可以是求一元函数 h(α)h(\alpha)h(α) 的精确最小值点,也可以求一个使得目标函数下降足够 多的 α\alphaα 作为步长。

  • 对于多元目标函数 f(x),x∈Rdf(\boldsymbol{x}) , \boldsymbol{x} \in \mathbb{R}^df(x)xRd, 有一种优化方法是先沿 x0x_0x0 坐标轴方向搜索,再沿 x1x_1x1 坐标轴方向搜索,直到沿 xdx_dxd 坐标轴方向搜索后再重复地从 x0x_0x0 坐标轴方向开始, 这种方法叫做坐标循环下降法。

  • 一元函数的求根问题和优化问题使用的算法类似,下面讨论一元函数的优化和求根问题。

1. 二分法求根

优化问题与求根问题密切相关,很多优化问题会归结为一个求根问题。对一元目标函数 f(x)f(x)f(x) ,若 f(x)f(x)f(x) 连续 可微,极值点一定是 f′(x)=0f^{\prime}(x)=0f(x)=0 的根。二分法是实际数值计算中一元函数求根使用最多的方法, 这种方法简单而又有比较高的收敛速度。

设函数 f(x)f(x)f(x) 在闭区间 [a,b][a, b][a,b] 连续, 且 f(a)f(b)≤0f(a) f(b) \leq 0f(a)f(b)0 ,由零点定理,至少有一个点 x∗∈[a,b]x^* \in[a, b]x[a,b] 使得 f(x∗)=0f\left(x^*\right)=0f(x)=0 。如果 f(x)f(x)f(x)[a,b][a, b][a,b] 上还是严格单调函数则解 x∗x^*x 存在是唯一的。

一般使用二分法求根时需要函数是单调的(不妨设单调递增)。

1.1 [a,b]区间二分法求根

1.1.1 原理

二分法求根用区间 [a,b][a, b][a,b] 中点 ccc 处函数值 f(c)f(c)f(c) 的正负号来判断根在区间中点的左边还是右边,显然,如果 f(c)f(c)f(c)f(a)f(a)f(a) 异号,则 [a,c][a, c][a,c] 中有根;如果 f(c)f(c)f(c)f(b)f(b)f(b) 异号,则 [c,b][c, b][c,b] 中有根。根据这样的想法,可以迭代地每次用法如下:

设真实根为 x∗x^*x ,第 kkk 步的区间中点为 x(k)x^{(k)}x(k) ,则
∣x(k)−x∗∣≤(b−a)(12)k,\left|x^{(k)}-x^*\right| \leq(b-a)\left(\frac{1}{2}\right)^k, x(k)x(ba)(21)k,
二分法具有线性收敛速度。

1.1.2 C++实现

求解x2−ln⁡x=0x^2-\ln x=0x2lnx=0的根。含根的区间为[0,2][0,2][0,2]

//
// Created by CHH3213 on 2022/9/12.
//
#include <valarray>
#include<iostream>
using namespace std;
#define EPS 1e-6
/** 使用二分法求解方程的根:np.log(x)+x^2=0*/
double func(double x){/*** 构造函数* x:自变量* return:函数值*/return log(x)+x*x;
}double bisection(double a, double b){/*** 二分法求根* [a,b]:  含有根的区间*/if(a>b)swap(a,b);//确保a < bdouble y_a = func(a),y_b =func(b);if(y_a==0){// 已经是根b=a;return a;}if(y_b==0){// 已经是根a=b;return b;}while(b-a>EPS){double x = a+(b-a)/2;double y = func(x);if(y==0){a=x,b=x;break;}else if(y*y_a>=0){ // 根在右半边a=x;}else{//根在左半边b=x;}}return a;
}
int main(){cout<<"answer: "<<bisection(0.0,2.0)<<"----prove: "<<func(bisection(0.0,2.0)) <<endl;return 0;
};

求出的根为

answer: 0.652918----prove: -2.20888e-006

1.2 区间右侧无穷的二分法求根

如果 f(x)f(x)f(x)[a,∞)[a, \infty)[a,) 区间上的严格单调的连续函数, 且 lim⁡x→∞f(x)\lim _{x \rightarrow \infty} f(x)limxf(x)f(a)f(a)f(a) 反号,则 f(x)f(x)f(x)[a,∞)[a, \infty)[a,) 上存在唯 一的根, 这时需要先找到闭区间 [a,b][a, b][a,b] 使得 f(a)f(a)f(a)f(b)f(b)f(b) 反号,二分法算法需要略作调整:

其它的情况,比如 f(x)f(x)f(x) 定义在 (−∞,∞),(a,b)(-\infty, \infty),(a, b)(,),(a,b) 的情况可类似处理, 都需要先找到使得区间端点函数值符号 相反的闭区间。

1.3 求含根区间

如果需要找出哪个闭区间含根,需要使用求含根区间的算法,假设初始步长为h0h_0h0

求出含根的闭区间后再使用二分法进行求根。

2. 牛顿法求根

2.1 原理

假设我们要求f(x)=0f(x)=0f(x)=0的根,牛顿法的求解步骤如下:

给定一 个初值 x0x_0x0 ,在 x0x_0x0 处用一阶泰勒展式来近似表示函数 f(x)f(x)f(x)
f(x)=f(x0)+f′(x0)(x−x0)(1)\tag{1} f(x)=f\left(x_0\right)+f^{\prime}\left(x_0\right)\left(x-x_0\right) f(x)=f(x0)+f(x0)(xx0)(1)
f(x)=0f(x)=0f(x)=0 带入公式 (1)(1)(1) ,求得与 xxx 轴交点横坐标 x=x0−f(x0)/f′(x0)x=x_0-f\left(x_0\right) / f^{\prime}\left(x_0\right)x=x0f(x0)/f(x0) ,这个 xxx 点并 不是函数 f(x)f(x)f(x) 的根,但是距离真正的根更近了一点,如下图所示。

将上一步所求的 xxx 值作为 x1x_1x1 值,那么 x1=x0−f(x0)/f′(x0)x_1=x_0-f\left(x_0\right) / f^{\prime}\left(x_0\right)x1=x0f(x0)/f(x0)x1x_1x1 值处用一阶泰勒展式:
f(x)=f(x1)+f′(x1)(x−x1)(2)\tag{2} f(x)=f\left(x_1\right)+f^{\prime}\left(x_1\right)\left(x-x_1\right) f(x)=f(x1)+f(x1)(xx1)(2)
f(x)=0f(x)=0f(x)=0 带入公式 (2)(2)(2) ,求得交点 x=x1−f(x1)/f′(x1)x=x_1-f\left(x_1\right) / f^{\prime}\left(x_1\right)x=x1f(x1)/f(x1) ,依次迭代进而推出公式 (3)
xn+1=xn−f(xn)/f′(xn)(3)\tag{3} x_{n+1}=x_n-f\left(x_n\right) / f^{\prime}\left(x_n\right) xn+1=xnf(xn)/f(xn)(3)
最终求得的 xxx 值变化小于预先设定的精度就认为这个 xxx 值是函数 f(x)f(x)f(x) 的近似根,此时牛顿法收敛。

2.2 c++实现

求解x2−ln⁡x=0x^2-\ln x=0x2lnx=0的根。

//
// Created by CHH3213 on 2022/9/12.
//
#include<iostream>
#include <valarray>using namespace std;#define DELTA 1e-4
#define EPS 1e-6
/** 使用牛顿法求解方程的根:-np.log(x)+x^2=0* 步骤:原函数->构造损失函数->对损失函数求导->进行梯度下降*/
double func(double x){/*** 构造函数* x:自变量* return:函数值*/return log(x)+x*x;
}double func_prime(double x){/*** 计算函数导数,以导数定义的方式求解*/return func(x+DELTA)-func(x-DELTA)/(2*DELTA);
}
double Newton(double x0){double x = x0;double x_last=0.1;while((x-x_last)>EPS){x_last=x;x=x_last-func(x_last)/ func_prime(x_last);}return x;
}int main(){cout<<"answer: "<<Newton(0.5)<<"----prove: "<<func(Newton(0.5)) <<endl;return 0;
}

求出的根为

answer: 0.652899----prove: -5.607e-005

3. 梯度下降法求根

梯度下降算法一般用于求解最值问题,但同样也可以求解方程f(x)f(x)f(x)的根。求解方程的根即求解在哪个点f(x)f(x)f(x)离0的距离最近。数学上定义两个数距离就是绝对值,但是因为绝对值不便于计算,所以将其替换成等价的差的平方,即损失函数:
loss=(f(x)−0)2loss = (f(x)-0)^2 loss=(f(x)0)2

求解方程的根,就是找到一个点使得构造的损失函数最小,这样就转化成了求最值问题。

3.1 c++实现

求解二次方程x2+2x−3=0x^2+2x-3=0x2+2x3=0的根。

我们通过设置不同的初值找出这个二次方程的根。

//
// Created by CHH3213 on 2022/8/18.
//
#include<iostream>
#include <valarray>
/** 使用梯度下降法求解二次方程的根* 步骤:原函数->构造损失函数->对损失函数求导->进行梯度下降*/
using namespace std;#define DELTA 1e-4
#define EPS 1e-6
//y=ax^2+bx+c
double func(double a,double b,double c,double x){return a*pow(x,2)+b*x+c;
}//构造损失函数
double loss_func(double a,double b,double c,double x){return pow(func(a,b,c,x)-0,2);
}//构造损失函数导数
double loss_func_prime(double a,double b,double c,double x){return (loss_func(a,b,c,x+DELTA)-loss_func(a,b,c,x))/DELTA;
}double GradientDescent(double a,double b,double c,double x0,double learning_rate ){/*** 梯度下降算法* a,b,c为二次函数的系数* x0为迭代初值* learning_rate为学习率*/double x = x0;while(abs(loss_func(a,b,c,x))>EPS){x = x-learning_rate* loss_func_prime(a,b,c,x);}return x;
}
int main(){double a = 1.0,b=2.0,c=-3.0;double x0=-b/(2*a)-1;//通过设置不同初值找出来double x1= GradientDescent(a,b,c,x0,0.01);x0=-b/(2*a)+1;double x2= GradientDescent(a,b,c,x0,0.01);cout<<x1<<" "<<x2<<endl;
}

4. 一维搜索的区间

4.1 一般一维搜索方法

  • 对一元连续函数 f(x)f(x)f(x) ,若存在 A<x∗<BA<x^*<BA<x<B 使得 f(x)f(x)f(x)(A,x∗]\left(A, x^*\right](A,x] 单调下降,在 [x∗,B)\left[x^*, B\right)[x,B) 单调上升,则称 f(x)f(x)f(x)(A,B)(A, B)(A,B) 是单谷的。这时,若存在 A<a<c<b<BA<a<c<b<BA<a<c<b<B 使得 f(c)<f(a),f(c)<f(b)f(c)<f(a), f(c)<f(b)f(c)<f(a),f(c)<f(b) ,则 x∗x^*x 必 在 (a,b)(a, b)(a,b) 中。这是因为如果 x∗≤ax^* \leq axa ,则 a,c,ba, c, ba,c,b 三个点在单调上升分支, 必有 f(a)≤f(c)≤f(b)f(a) \leq f(c) \leq f(b)f(a)f(c)f(b) , 如果 x∗≥bx^* \geq bxba,c,ba, c, ba,c,b 三个点在单调下降分支,必有 f(a)≥f(c)≥f(b)f(a) \geq f(c) \geq f(b)f(a)f(c)f(b) , 都会导致矛盾。

  • 设定义于 (−∞,∞)(-\infty, \infty)(,)(0,∞)(0, \infty)(0,) 的连续目标函数 f(x)f(x)f(x) 存在局部极小值点 x∗x^*x, 且设 f(x)f(x)f(x)x∗x^*x 的一个邻域内是单 谷的, 则只要能找到三个点 a<c<ba<c<ba<c<b 使得 f(a)>f(c),f(c)<f(b)f(a)>f(c), f(c)<f(b)f(a)>f(c),f(c)<f(b) ,则在 (a,b)(a, b)(a,b) 内必存在 f(x)f(x)f(x) 的一个极 小值点。

  • 为了求 a,ba, ba,b, 从两个初始点 x0,x1x_0, x_1x0,x1 出发,如果 f(x0)>f(x1)f\left(x_0\right)>f\left(x_1\right)f(x0)>f(x1) ,则最小值点可能在 x1x_1x1 右侧,向右侧搜索找到 一个函数值超过 f(x1)f\left(x_1\right)f(x1) 的点 x2x_2x2 ,这时最小值点应该在 (x0,x2)\left(x_0, x_2\right)(x0,x2) 内部; 如果 f(x0)<f(x1)f\left(x_0\right)<f\left(x_1\right)f(x0)<f(x1) ,则最小值点可 能在 x0x_0x0 左侧,向左侧搜索。

  • 如果函数 f(x)f(x)f(x) 的定义域为 x∈(0,∞)x \in(0, \infty)x(0,) ,以上的算法应取初值 x0>0x_0>0x0>0 ,如果出现向左搜索,可取迭代公式为 xk+1=1γxkx_{k+1}=\frac{1}{\gamma} x_kxk+1=γ1xk

  • 如果目标函数 f(x)f(x)f(x) 连续可导,则求最小值点所在区间也可以通过求 a<ba<ba<b 使得 f′(a)<0,f′(b)>0f^{\prime}(a)<0, f^{\prime}(b)>0f(a)<0,f(b)>0 来解决。可取初值 x0x_0x0 ,如果 f′(x0)<0f^{\prime}\left(x_0\right)<0f(x0)<0 ,则类似上面算法那样向右搜索找到 bbb 使得 f′(b)>0f^{\prime}(b)>0f(b)>0 ; 如果 f′(x0)>0f^{\prime}\left(x_0\right)>0f(x0)>0 ,则向左搜索找到 a<x0a<x_0a<x0 使得 f′(a)<0f^{\prime}(a)<0f(a)<0 。用最后得到的两个点作为 a,ba, ba,b 。可以看出,这里描述的搜索方法适用于一元函数求根时寻找包含根的区间的问题。

4.2 黄金分割法(0.618)

4.2.1 原理

0.618法(黄金分割法)是一种常用的不需要导数信息的一维搜索方法。假设 f(x)f(x)f(x) 在闭区间 [a,b][a, b][a,b] 内是单谷的,存在最小值点 x∗∈(a,b)x^* \in(a, b)x(a,b) , 这时可以用 0.6180.6180.618 法求最小值点。

在区间 [a,b][a, b][a,b] 内对称地取两个点 c<dc<dc<d 在所谓的黄金分割点上, 即
d−ab−a=ρ≜5−12≈0.618,b−cb−a=ρ,\frac{d-a}{b-a}=\rho \triangleq \frac{\sqrt{5}-1}{2} \approx 0.618, \quad \frac{b-c}{b-a}=\rho, bada=ρ2510.618,babc=ρ,
黄金分割比例 ρ\rhoρ 满足
1−ρρ=ρ,\frac{1-\rho}{\rho}=\rho, ρ1ρ=ρ,

  • 这样的比例的特点是,当区间缩小到 [a,d][a, d][a,d] 时, ccc 仍为缩小后的区间的右侧黄金分割点;当区间缩小到 [c,b][c, b][c,b] 时, ddd 仍为缩小后的区间的左侧黄金分割点。

  • 这样选了 c,dc, dc,d 两个点后,比较 f(c)f(c)f(c)f(d)f(d)f(d) 的值,如果 f(c)f(c)f(c) 较 小,则因为 a<c<d,f(a)>f(c),f(c)<f(d)a<c<d, f(a)>f(c), f(c)<f(d)a<c<d,f(a)>f(c),f(c)<f(d), 最小值点 x∗x^*x 一定在区间 [a,d][a, d][a,d] 内,可以把搜索区间缩 小到 [a,d][a, d][a,d], 以 [a,d][a, d][a,d] 作为含有最小值点的区间再比较其中两个黄金分割点的函数值,而且这时 ccc[a,d][a, d][a,d] 中右 侧的黄金分割点,只要再添加左侧的黄金分割点就可以了。

  • 如果比较 f(c)f(c)f(c)f(d)f(d)f(d) 时发现 f(d)f(d)f(d) 较小,则把搜 索区间缩小到 [c,b][c, b][c,b], 这时 ddd[c,b][c, b][c,b] 内的左侧黄金分割点,只要再添加右侧黄金分割点。每次迭代使得区间长 度缩小到原来的0.618倍, 缩小后的两个黄金分割点中一个的坐标和函数值是已经算过的。

设规定的最小值点绝对误差限为 ϵ\epsilonϵ ,算法如下:

0.618法具有线性收敛速度。

0.618n(b−a)≤ϵ⇒n≥ln⁡ϵb−aln⁡0.6180.618^n(b-a)\leq \epsilon\Rightarrow n\ge\frac{ \ln\frac{\epsilon}{b-a}}{\ln 0.618} 0.618n(ba)ϵnln0.618lnbaϵ

4.2.2 c++实现

求解函数f(x)=x2−5f(x)=x^2-5f(x)=x25迭代nnn次后的最小值区间。每次迭代区间长度减小到原来的0.618倍。

//
// Created by CHH3213 on 2022/9/12.
//
#include <valarray>
#include<iostream>
#include <vector>using namespace std;
#define EPS 1e-6
/** 使用黄金搜索法求解迭代n次后的含最小值区间,:f(x)=x^2-5*/
double func(double x){/*** 构造函数,单谷函数* x:自变量* return:函数值*/return x*x-5;
}vector<double> golden_section_search(double a, double b,int n){/***  含最小值的区间[a,b]* n: 迭代次数*/double rho = (sqrt(5)-1)/2.0;//0.618黄金分割比double c=rho*a+(1-rho)*b;//(a, b)中靠近a的黄金分割点double d = rho*b+(1-rho)*a;//(a,b)中靠近b的黄金分割点while(n--){if(func(c)>func(d)){//这时(c, b)是含最小值区间, d是(c, b)的中靠近c的黄金分割点, 仍用a, b表示含最小值区间,c表示靠近a的黄金分割点a=c;c=d;d= rho*b+(1-rho)*a;//(a,b)中靠近b的黄金分割点}else{//这时(a, d)是含最小值区间,c是区间(a,d)的靠近d的黄金分割点,仍用a, b表示含最小值区间,d表示靠近b的黄金分割点b=d;d=c;c=rho*a+(1-rho)*b;}}return {a,b};
}int main(){vector<double> res = golden_section_search(-2,2,10);cout<<res[0]<<' '<<res[1]<<endl;return 0;
}

迭代10次的结果为

-0.0263112 0.00621124

用黄金分割法求解最小值也很简单,只要迭代次数够多,或者设置b−ab-aba的精度达到预设的阈值即可。

进一步地,如果是求f(x)=x2−5=0f(x)=x^2-5=0f(x)=x25=0的根,那么可以构造损失函数,求解损失函数的最小值也就是求解方程的根。代码相比之前的改动很小:

//
// Created by CHH3213 on 2022/9/12.
//
#include <valarray>
#include<iostream>
#include <vector>using namespace std;
#define EPS 1e-6
/** 使用黄金搜索法求解迭代n次后的方程的根所在区间:f(x)=x^2-5=0*/
double func(double x){//构造损失函数(x^2-5)^2return pow(x*x-5,2);
}vector<double> golden_section_search(double a, double b,int n){/***  含最小值的区间[a,b]* n: 迭代次数*/double rho = (sqrt(5)-1)/2.0;//0.618黄金分割比double c=rho*a+(1-rho)*b;//(a, b)中靠近a的黄金分割点double d = rho*b+(1-rho)*a;//(a,b)中靠近b的黄金分割点while(n--){if(func(c)>func(d)){//这时(c, b)是含最小值区间, d是(c, b)的中靠近c的黄金分割点, 仍用a, b表示含最小值区间,c表示靠近a的黄金分割点a=c;c=d;d= rho*b+(1-rho)*a;//(a,b)中靠近b的黄金分割点}else{//这时(a, d)是含最小值区间,c是区间(a,d)的靠近d的黄金分割点,仍用a, b表示含最小值区间,d表示靠近b的黄金分割点b=d;d=c;c=rho*a+(1-rho)*b;}}return {a,b};
}int main(){vector<double> res = golden_section_search(-3,3,20);cout<<res[0]<<' '<<res[1]<<endl;return 0;
}

4.3 抛物线法

4.3.1 原理

为了用二次多项式逼近 f(x)f(x)f(x) ,只 要有 f(x)f(x)f(x) 函数图像上的三个点就可以。仍假设 f(x)f(x)f(x) 在闭区间 [a,b][a, b][a,b] 内是单谷的,存在最小值点 x∗∈(a,b)x^* \in(a, b)x(a,b) 。 设 c∈(a,b)c \in(a, b)c(a,b), 利用 (a,f(a)),(c,f(c)),(b,f(b))(a, f(a)),(c, f(c)),(b, f(b))(a,f(a)),(c,f(c)),(b,f(b)) 三个点求得二次插值多项式 φ(x)\varphi(x)φ(x) ,用 φ(x)\varphi(x)φ(x) 的最小值点 作为下一个近似值。

二次插值多项式知识点可以参考这篇博客。

设插值多项式为
φ(x)=β0+β1x+β2x2,\varphi(x)=\beta_0+\beta_1 x+\beta_2 x^2, φ(x)=β0+β1x+β2x2,
其中 β2>0\beta_2>0β2>0, 在给定了 a<c<ba<c<ba<c<b 和相应函数值后,可以解出
β2=1b−a[f(b)−f(c)b−c−f(c)−f(a)c−a],β1=f(c)−f(a)c−a−β2(c+a),\begin{aligned} \beta_2 &=\frac{1}{b-a}\left[\frac{f(b)-f(c)}{b-c}-\frac{f(c)-f(a)}{c-a}\right], \\ \beta_1 &=\frac{f(c)-f(a)}{c-a}-\beta_2(c+a), \end{aligned} β2β1=ba1[bcf(b)f(c)caf(c)f(a)],=caf(c)f(a)β2(c+a),
从而求得 φ(⋅)\varphi(\cdot)φ() 的最小值点
x~=−β12β2\tilde{x}=-\frac{\beta_1}{2 \beta_2} x~=2β2β1

  • 如果 x~<c\tilde{x}<cx~<c, 则以 a,x~,ca, \tilde{x}, ca,x~,c 为新的插值节点继续计算插值多项式并求插值多项式的最小值点;
  • 如果 x~>c\tilde{x}>cx~>c, 则以 c,x~,bc, \tilde{x}, bc,x~,b 为新的插值节点继续计算插值多项式并求插值多项式的最小值点,如此迭代直至三个插值点足够接 近。

适当条件下抛物线法达到超线性收敛速度。

4.3.2 c++实现

求解函数f(x)=x2−5f(x)=x^2-5f(x)=x25的最小值点。

//
// Created by CHH3213 on 2022/9/12.
//
#include<iostream>
#include <valarray>
/** 使用抛物线法求解 x*x-5的最小值点*/
using namespace std;#define DELTA 1e-4
#define EPS 1e-6
double func(double x){/*** 构造函数* x:自变量* return:函数值*/return x*x-5;
}double quadratic_fit_search(double a,double b,double c,int n){/*** 抛物线法;* 区间(a,b);* a<c<b* n: 迭代次数*/while(n--){double beta_1 = 1/(b-a)*((func(b)-func(c))/(b-c)-(func(c)- func(a))/(c-a));double beta_2 = (func(c)-func(a))/(c-a)-beta_2*(c+a);double x = -beta_1/(2*beta_2);if(x<c){b=c;c=x;}else{a=c;c=x;}}return c;
}int main(){cout<<quadratic_fit_search(-3,3,1,10)<<endl;return 0;
}

4.3.3 改进

4.3.14.3.14.3.1 的算法 迭代不保证最小值点在拟合抛物线所用的三个点构成的区间内。下面是改进的做法。

对一元单谷函数 f(x)f(x)f(x) , 取三个点 a<b<ca<b<ca<b<c 使得 f(a)>f(b)f(a)>f(b)f(a)>f(b), f(c)>f(b)f(c)>f(b)f(c)>f(b)

在迭代过程中要求每一步产生的新的 a<b<ca<b<ca<b<c 都 满足 f(a)>f(b),f(c)>f(b)f(a)>f(b), f(c)>f(b)f(a)>f(b),f(c)>f(b) , 即最小值一定在 (a,c)(a, c)(a,c) 内。我们可以直接利用Lagrange插值公式写出二次多项 式,并用导数等于零解出多项式的最小值点,可得从 a,b,ca, b, ca,b,c 计算下一个点的迭代公式:
x∗=12ya(b2−c2)+yb(c2−a2)+yc(a2−b2)ya(b−c)+yb(c−a)+yc(a−b)x^*=\frac{1}{2} \frac{y_a\left(b^2-c^2\right)+y_b\left(c^2-a^2\right)+y_c\left(a^2-b^2\right)}{y_a(b-c)+y_b(c-a)+y_c(a-b)} x=21ya(bc)+yb(ca)+yc(ab)ya(b2c2)+yb(c2a2)+yc(a2b2)
产生 x∗x^*x 后,利用 a,b,c,x∗a, b, c, x^*a,b,c,x 这四个点中找到含最小值的缩小的区间并仍用 a,b,ca, b, ca,b,c 三个点表示。

4.3.4 c++实现

求解函数f(x)=x2−5f(x)=x^2-5f(x)=x25的最小值点。

//
// Created by CHH3213 on 2022/9/12.
//
#include<iostream>
#include <valarray>
/** 使用抛物线法求解 x*x-5的最小值点*/
using namespace std;#define DELTA 1e-4
#define EPS 1e-6
double func(double x){/*** 构造函数* x:自变量* return:函数值*/return x*x-5;
}double quadratic_fit_search_2(double a,double b,double c,int n){/*** 抛物线法;* 区间(a,c);* a<b<c* n: 迭代次数* return: 最小值点*/while(n--){double y_a=func(a),y_b=func(b),y_c=func(c);double x = 0.5*(y_a*(b*b-c*c)+y_b*(c*c-a*a)+y_c*(a*a-b*b))/(y_a*(b-c)+y_b*(c-a)+y_c*(a-b));double y_x = func(x);if(x>b){if(y_x>y_b){   //用 a < b < x 作为新的起点c=x;}else{     //用 b < x < c作为新的起点a=b;b=x;}}else if(x<b){if(y_x>y_b){   //用 x < b < c作为新的起点a=x;}else{     //用 a < x < b作为新的起点c=b;b=x;}}}return b;}int main(){cout<<quadratic_fit_search_2(-2,2,3,50)<<endl;return 0;
}

同样地,如果要求方程的根,构造损失函数,求损失函数的最小值点就是在求方程的根。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_6566.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K8s部署SpringBoot项目简单例子

目录 前言 前提条件 正文 1. 获取镜像 2. 空运行测试生成部署yaml文件 3. 修改yaml文件&#xff0c;增加镜像拉取策略 4. 以yaml文件的方式部署springboot项目 5. 查看部署pod的状态 6. 暴露服务端口 7.通过浏览器访问服务 前言 本文通过将一个构建好的springboot的…

Linux服务器上通过miniconda安装R(2022)

安装miniconda 下载最新版miniconda wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh安装 bash Miniconda3-latest-Linux-x86_64.sh这一步骤里我们输入完命令后会有个License要读&#xff0c;一行一行读的话按Enter&#xff0c;不想读就直接输…

【uiautomation】获取微信好友名单,可指定标签 全部

前言 接到了一个需求&#xff1a;现微信有8000好友&#xff0c;需要给所有好友发送一则一样的消息。网上搜索一番后&#xff0c;发现uiautomation 可以解决该需求&#xff0c;遂有此文。这是第一篇&#xff0c;获取全部好友 代码在文章末尾&#xff0c;自取~ 微信群发消息链接 …

一个画廊的GIF动画动作英雄从80年代和90年代

你还记得那些80年代和90年代初的动作英雄吗?比如查克诺里斯、史蒂文西格尔、西尔维斯特史泰龙、让克劳德范达姆,当然还有阿诺德施瓦辛格?意大利天才设计师DavideMazuchin&;郭美雄创建了一个图文并茂的GIF画廊,名为“过去的动作英雄”,以纪念那些年轻时的经典英雄。以…

不同vlan之间实现通信

目录: 1、单臂路由实现不同vlan间通信的原理 2、单臂路由的缺陷 3、单臂路由的配置 4、三层交换 不同vlan之间实现通信 单臂路由链路类型:交换机连接主机的端口位为access链路交换机连接路由器的的端口为trunk链路子接口:路由器的物理接口可以被划分成多个逻辑接口每个子接口…

【云原生】Kubernetes CRD 详解(Custom Resource Definition)

文章目录一、概述二、定制资源1&#xff09;定制资源 和 定制控制器2&#xff09;定制控制器3&#xff09;Operator 介绍1、Operator Framework2、Operator 安装3、安装 Operator SDK4、Operator 简单使用4&#xff09;Kubernetes API 聚合层5&#xff09;声明式 APIs6&#xf…

HTML 快速入门

HTML代码是“标签化”的代码&#xff0c;把一个HTML文件视为一个文档&#xff0c;文档中有很多的标签&#xff0c;每一个标签也可以称为一个元素&#xff0c;同时每一个元素也对应一个对象&#xff0c;对象中有属性和方法。HTML的标签除了部分标签外&#xff0c;其他的都是成对…

易网防伪防窜货溯源管理系统源码

防伪防窜货和溯源系统更好用更易用&#xff0c;系统由PHPmysql开发&#xff0c;安全稳定。系统以防伪码(溯源码)为中心&#xff0c;可非常方便的为防伪码赋值产品信息&#xff0c;溯源信息。是建立防伪防窜货和溯源追踪系统的不二选择。 系统功能介绍&#xff1a; 一、防伪码管…

【RuoYi-Vue-Plus】学习笔记 40 - Validator(一)校验器对 Model 属性校验调用流程分析

文章目录前言参考目录框架集成1、Maven2、校验框架配置类 ValidatorConfig3、测试方法4、接口测试4.1、校验失败&#xff08;参数为 null&#xff09;4.2、校验成功&#xff08;参数不为 null&#xff09;执行流程分析InvocableHandlerMethod#invokeForRequestInvocableHandler…

来自邦卡的神奇扁平超级英雄插图

平面设计趋势正在相当大程度上动摇平面设计行业的各个方面。我们正在进入一个简单和最低限度的沟通模式的新时代,在这个时代中,平面设计似乎以最好的方式提供。 受平面设计形式的启发,法国平面设计师邦卡采用了相同的方法,创作了一系列简约、平面的超级英雄插图。这些插图涵…

自制操作系统日志——第二十二天

自制操作系统日志——第二十二天 今天&#xff0c;我们将继续再完善一下保护操作系统的内容&#xff0c;以及进一步的利用c语言显示字符串&#xff01; 文章目录自制操作系统日志——第二十二天一、保护操作系统3手动强制关闭应用程序二、用c语言显示字符串API 显示窗口总结一…

vivado使用方法(初级)

文章目录1 创建新工程1.1 工程创建1.2 新建Verilog文件1.3 仿真参考1 创建新工程 1.1 工程创建 1、首先打开Vavido软件&#xff0c;点击Creat Project或者在File——>Project——>New里面进行新工程的创建 2、然后在弹出的界面上点击Next进入下一个界面进行项目的命名…

全站最简单 “数据滚动可视化大屏” 【JS基础拿来即用】

源码获取方式&#xff1a; 数据滚动大屏源码&#xff0c;原生js实现超级简单-Javascript文档类资源-CSDN下载原生js实现的数据滚动大屏案例&#xff0c;实现应该是全网最简单的&#xff0c;拿来直接使用即可&#xff0c;没有会员的小伙伴去我文章主更多下载资源、学习资料请访问…

基于Python实现的遗传算法求TSP问题

遗传算法求TSP问题 目录 人工智能第四次实验报告 1 遗传算法求TSP问题 1 一 、问题背景 1 1.1 遗传算法简介 1 1.2 遗传算法基本要素 2 1.3 遗传算法一般步骤 2 二 、程序说明 3 2.3 选择初始群体 4 2.4 适应度函数 4 2.5 遗传操作 4 2.6 迭代过程 4 三 、程序测试 5 3.1 求解…

Vue3+elementplus搭建通用管理系统实例七:通用表格实现上

一、本章内容 使用配置的方式实现表格的界面的自动生成、自动解析实体配置信息,并生成表格列、筛选项等功能,完整课程地址 二、效果预览 三、开发视频

动手实现深度学习(12): 卷积层的实现

9.1 卷积层的运算 传送门: https://www.cnblogs.com/greentomlee/p/12314064.html github: Leezhen2014: https://github.com/Leezhen2014/python_deep_learning 卷积的forward 卷积的计算过程网上的资料已经做够好了,没必要自己再写一遍。只把资料搬运到这里: http://deepl…

【进击的JavaScript|高薪面试必看】JS基础-作用域和闭包

六年代码两茫茫&#xff0c;不思量&#xff0c;自难忘 6年资深前端主管一枚&#xff0c;只分享技术干货&#xff0c;项目实战经验&#xff0c;面试指导 关注博主不迷路~ 本系列文章是博主精心整理的面试热点问题&#xff0c;吸收了大量的技术博客与面试文章&#xff0c;总结多年…

Java毕设项目——网上宠物店管理系统(java+SSM+Maven+Mysql+Jsp)

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM 技术&#xff1a;Jsp JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a…

收银台——Web自动化测试

目录 一&#xff0c;收银台项目的主要功能&#xff1a; 二&#xff0c;Web自动化测试 一&#xff0c;Web自动化测试&#xff0c;设计测试用例 二&#xff0c;编写测试用例代码 三&#xff0c;测试结果&#xff1a; 四&#xff0c;总结&#xff1a; 一&#xff0c;收银台项…

JVM监控:JMX组件与底层原理

JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架 &#xff0c;从Java5.0开始引入到标准Java技术平台中。JMX是一套标准的代理和服务&#xff0c;实际上&#xff0c;用户可以在任何Java应用程序中使用这些代理和服务实现管理。 其实JMX也可以看作一个框架&a…