黄金分割法是一种区间收缩方法。
所谓区间收缩方法,指的是将含有最优解的区间逐步缩小,直至区间长度为零的方法。比如,为求函数f(x)在区间[a,b]上的最小值点,可在该区间中任取两点x1、x2,通过比较函数f(x)在这两点的函数值或者导数值等,来决定去掉一部分区间[a,x1]或者[x2,b],从而使搜索区间长度变小,如此迭代,直至区间收缩为一点为止,或区间长度小于某给定的精度为止。
对于区间[a,b]上的单峰函数f(x),可以在其中任意选取两点x1、x2,通过比较这两点的函数值,就可以将搜索区间缩小。比如说,如果f(x1)<f(x2),则选取[a1,b1]=[a,x2],如果f(x1)> f(x2),则选取[a1,b1]=[x1,b],如果f(x1)=f(x2),则选取[a1,b1]=[x1,x2],这样就得到f(x)的更小的搜索区间[a1,b1],然后根据这一方法再进行划分,得到一系列搜索区间满足
于是对事先给定的某个精度ε,当
时,可以将f(x)的最小值点近似地取为
单峰函数与搜索区间的定义如下:
如何选取x1和x2才能使得算法的效率更高?
这里思念家乡的古诗100首推导过程不在详细讨论,直接给出满足对称取点、等比收缩和单点计算三个原则的分点。
或者
算法描述如下:
这个算法非常理想,整个迭代过程中。除最初计算分点时使用过一次乘法外,后边的分点全部都由加减法完成,并且每次迭代只需计算一个分点的函数值。但是,在实际应用中,该方法存在一定的缺陷。这种缺陷主要来源于无理数(-1+√5)/2的取值。这里我们只取了小数点后三位数。因而有一定误差,所以在瞧这两家子迭代过程中,经过多次累计,误差就会很大,从而导致最终选取的两点并不一定是我们所期望的那两点,事实上,常常发生x2小于x1的情形。
为避免这种情况的出现,我们也可以通过将无理数(-1+√5)/2小数点后面的位数提高来避免算法的这一缺陷。不过这样做的效果未必很好。因为我们不知道在算法中到底要经过多少次迭代,当迭代次数很大时,这种做法依然是不能奏效的。因此,我们在程序中每次计算分点时不得不根据算法原理,使用一次乘法,即第二个分点不用加减法产生,而直接用乘法计算得出。由此即可避免累计误差所带来的缺陷。我们仍假设f(x)是区间[a,b]上的单峰函数。修改后的黄金分割法的计算框图如下图所示。
修改后的黄金分割算法如下:
用黄金分割法求函数 f(x)=x³-12x-11在区间[0,海蓝宝的作用10]上的最小值点,取ε=0.01。
import java.math.bigdecimal;/** * 黄金分割法测试 */public class goldencut { public static final bigdecimal c=new bigdecimal("0.01"); public static bigdecimal end=null; /** *x^3-12x-11 * @param x 输入参数x * @return x^3-12x-11 */ public static bigdecimal computefx(bigdecimal x){ return x.pow(3).subtract(new bigdecimal("12").multiply(x)).subtract(new bigdecimal("11")) .tscale(10,bigdecimal.round_half_even); } /** * a+0.382*(b-a) * @param a * @param b * @return a+0.382*(b-a) */ public static bigdecimal compute382(bigdecimal a,bigdecimal b){ return a.add(new bigdecimal("0.382").multiply(b.subtract(a))) .tscale(10,bigdecimal.round_half_even); } /** * a+0.618(b-a) * @param a * @param b * @return */ public static bigdecimal compute618(bigdecimal a,bigdecimal b){ return a.add(new国学感悟 bigdecimal("0.618").multiply(b.subtract(a))) .tscale(10,bigdecimal.round_half_even); } /** * a+b-x1 * @param a * @param b * @param x1 * @return */ public static bigdecimal subtractabx1(bigdecimal a,bigdecimal b,bigdecimal x1){ return a.add(b).subtract(x1) .tscale(10,bigdecimal.round_half_even); } //判断是否满足精度 b-a<c? public static boolean ok(bigdecimal a,bigdecimal b){ return b.subtract(a).compareto(c) < 0; } //输出最优解 public static bigdecimal success(bigdecimal a, bigdecimal b){ return (a.add(b)).divide(new bigdecimal("2")) .tscale(10,bigdecimal.round_half_even); } //修改后的黄金分割法 public static void goldentest1(bigdecimal a,bigdecimal b){ system.out.println("初始化"); bigdecimal x1=compute382(a,b); bigdecimal x2=subtractabx1(a,b,x1); bigdecimal f1=computefx(x1); bigdecimal f2=computefx(x2); system.out.println("x1="+x1); system.out.println("x2="+x2); system.out.println("f1="+f1); system.out.println("f2="+f2); system.out.println("迭代区间如下:"); int count=0; //迭代次数 while(!ok(a,b)){//只要不满足精度就一直迭代 system.out.println("["+a+"\t,\t"+b+"]"); count++; //迭代次数+1 if(f1.compareto(f2)==1){//f1>f2 a=x1; if(ok(a,b)){ //精度判断 end = success(a, b); break; }el{ f1=f2; 环保公益项目 x1=x2; x2=compute618(a,b); f2=computefx(x2); } }el{ b=x2; if(ok(a,b)){ end = success(a, b); break; }el{ f2=f1; x2=x1; x1=compute382(a,b); f1=computefx(x1); } } } system.out.println("迭代结束,迭代次数"+count); } public static void main(string[] args) { bigdecimal a=new bigdecimal("0"); bigdecimal b=new bigdecimal("10"); goldentest1(a,b); system.out.println("最优解为x*="+end); system.out.println("f(x*)="+computefx(end)); }}
由运行结果可以看到,迭代次数15次,最优解为x*=2.0009942948,f(x*)=-26.9999940673。迭代区间如下:
可以证明,黄金分割法是线性收敛的。
到此这篇关于java实现黄金分割法的示例代码的文章就介绍到这了,更多相关java黄金分割法内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-06 03:55:32,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/1e020b76fa5b972d27f89b8528c3ef75.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:Java实现黄金分割法的示例代码.doc
本文 PDF 下载地址:Java实现黄金分割法的示例代码.pdf
留言与评论(共有 0 条评论) |