如何实现求平⽅根的过程
回想初中,数学⽼师教我们体育的时候,不,是体育⽼师教我们数学的时候,好吧,我忘了我的数学是谁教的,都还给⽼师了。⽼师告诉我
们,求⼀个数的平⽅根,⽜顿爵爷想出了很好的⽅法。通过⼀个初始猜测值,去验证它的平⽅是否接近于被开⽅数。如果没有达到理想中的
接近状态,则基于这个初始值再做⼀次猜想。也就是获得这个值加上它除以被开⽅数所得的和的平均值。然后,同初始值⼀样进⾏验证,不
断的进⾏猜想,直到达到理想状态,最后我们就获得了理想中的平⽅根。
回想过去,年少⽆知。只知道相信⽼师讲的,不爱仔细思索。现在,在学sicp(计算机程序的构造与解释,江湖疯传的魔法书,我也买来啃⼀
啃)。在1.1.7⾥⾯讲到了如何⽤⽜顿法求平⽅根,勾起了我对平⽅根求解的思考,故总结以下简单思考。
⾸先,猜测值为什么需要从1开始,然后需要以这个值与它除以被开⽅数的商的和的平均数为改进值。⾸先我们可以回想⼀下函数曲线,y=
x²,它是开⼝向上,以y轴为对称轴的曲线。如果y确定,那么x值肯定落在x轴上值1和值y之间。因此,我们⾸先猜测x等于1.然后验证y除以
1得到的商与1的⼤⼩⽐较。如果刚好相等,恭喜你,x就是1。这种美好情况只会出现于y为1的情况。如果不相等,那么我们就得⽤1和y/1的
商的平均值a再去验证。直到我们猜想的这个值⾜够接近x.
假如y等于2分步描述如下:
猜测商平均数
12/1=2(1+2)/2=1.5
1.52/1.5=1.3333(1.5+1.3333)/2=1.4167
1.41672/1.4167=1.4118(1.4167+1.4118)/2=1.4142
1.4142......
functionguss(num,y){
return(y/num+num)/2;
}
functionisGoodEnough(num,y,differ){
((num,2)-y)<=differ;
}
functionsqrt(y,differ){
return(functionsqrtIter(num,y){
if(isGoodEnough(num,y,differ)){
returnnum;
}el{
returnsqrtIter(guss(num,y),y);
}
})(1,y)
}
这⾥涉及到为递归优化,后⾯我来修正⼀下,好冷啊,太穷,不敢开空调
继续昨天写的,观察sqrt函数,⾥⾯⽤了IIFE(⽴即执⾏函数表达式),这个sqrtIter函数语法形式上在尾部调⽤了⾃⾝,这就构成了递归调
⽤。但从计算模式上来看,其实是迭代的。有关语法形式和计算模式的区别,我会专门写⼀篇⽂章。⾸先,直观上看,sqrtIter已经构成了尾
递归。我们知道,递归会导致调⽤栈溢出,因为每⼀次函数调⽤,都会在已有栈上⽣成新的执⾏上下⽂。过多的执⾏上下⽂,⼀直得不到释
放,会导致调⽤栈的⼤⼩超过Javascript执⾏引擎所能容纳的最⼤栈⼤⼩。当然了,现代Javascrip执⾏引擎对这种尾递归进⾏了很好的优
化,基本原理就是,产⽣尾递归时,将前⾯⽆⽤的执⾏上下⽂出栈,然后尾调⽤形成的执⾏上下⽂⼊栈,这样尾递归就不会导致栈的⼤⼩⼀
直增⼤。但是,如果我们⾯临在⼀个很⽼的Javascript执⾏引擎该怎么办了。其实所有的递归写法,都可以以迭代的写法写出来。只是有时
候,递归的写法更直观⼀点。那么我们如何将上⾯的递归写法改为迭代写法了。
1.找到递归调⽤中值不断变化的变量num
2.找到递归调⽤中值不断变化的变量的变化⽅式guss(num,y)
3.找到递归调⽤中值不变的变量y,differ
4.找到递归调⽤弹出值的条件isGoodEnough(num,y,differ)
5.将递归调⽤改为迭代语法for,while,dowhile都可以
⽰例如下
functionsqrt(y,differ){
for(varnum=1;!isGoodEnough(num,y,differ);num=guss(num,y)){}
returnnum;
}
为了将我的思路表达清楚,所以我⽤了最常⽤的for循环。刚好契合for循环的初始语句,循环终⽌语句,迭代后执⾏语句。
写的有点乱,⼤家可以多多给我提意见。
本文发布于:2022-11-16 23:15:48,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/88/34303.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |