计算机与代数---如何计算sqrt---方法和实现

   日期:2020-11-15     浏览:77    评论:0    
核心提示:0.简介开根号可以用之前的pow方法计算,当然,还有一些更便捷的方法。1.二分法最常见的开根号方法就是二分法,计算,另,当n的值大于1的时候,可以让l = 0,r = n,当n<1的时候另l=0,r=1,然后利用如下代码计算出结果。long double l = 0, r = (n>=1 ? n:1), mid=0;while (fabs(mid * mid - n)>1e-8){ mid = (l + r) / 2; if (mid * mid > n)

0.简介

开根号可以用之前的pow方法计算,当然,还有一些更便捷的方法。

1.二分法

最常见的开根号方法就是二分法,计算,另,当n的值大于1的时候,可以让l = 0,r = n,当n<1的时候另l=0,r=1,然后利用如下代码计算出结果。

long double l = 0, r = (n>=1 ? n:1), mid=0;
while (fabs(mid * mid - n)>1e-8)//fabs(l-r)<1e-8
{
	mid = (l + r) / 2;
	if (mid * mid > n) r = mid;
	else l = mid;
}

2.牛顿迭代法

牛顿迭代法通过,来计算

首先找到曲线y上一点,一般取,此时得到点,在A点做切线,与x轴交于点B,这一步主要就是计算从开始,然后下一步A点应该怎么走能接近y=0的位置,从上图中可以看出A点要向B方向走才可以,这里为了方便计算,索性直接取下一个A点以,如下图。

这样一来,B点就逐渐接近y=0的点,经过多次迭代,使得,其中表示B的x轴坐标值,a是大于1的比较大的数字,当B点很接近y=0点的时候则找到了函数的解。牛顿迭代法在计算根号的时候,初始点要从函数向下凸的位置开始,因为每次算的切线与x轴交点都是在解的同一侧,只能是越来越逼近,不会导致计算结果不收敛。实际实现如下。

long double x = n,y = -1,k,b;
while (fabs(x*x-n)>1e-6)
{
	y = x * x - n;
	k = 2 * x;
	b = y - k * x;
	x = -(b / k);
}

3.问题

实际上,上面的主要思想领悟了,这个算法实现出来就好了 ,但是我实际上遇到了问题,当计算9000000000000000000000000000000000000000000000000000000000000000000.0的时候,算法竟然失效了,一直在死循环,经过调试我发现,上述两个方法,在fabs(x*x-n)<1e-6这里出现了问题,当数字很大的时候,浮点的底数计算多少会有一点不准确,一丁点误差,但是这一点误差由于有比较大的指数,所以误差实际会很大很大,导致fabs(x*x-n)<1e-6始终成立。并且在计算0.00000000000000000000000000000000000000000000000000000009的时候,由于数字过小,fabs(x*x-n)<1e-6不成立,在第一次无法进入进入循环,针对数字很大和很小的情况,我将要计算的数字都缩放到0.1-1.x之间,实际是(0.1,9.99999...)之间,这样就不会出现计算很大很小的数字,缩放的倍数都是10倍为基准,所以记录乘或者除了几个10,在最终结果上放大回来就可以了。所以有了如下的修改版。

double mysqrt(long double n)
{
	int tens_count = 0;
	double ten = 1;
	if (n > 1)
	{
		while(n > 1)
		{
			n /= 10;
			tens_count++;
		}
		//对于10倍数的奇偶个数要处理好
		if (tens_count % 2 == 1)
		{
			n *= 10;
			tens_count--;
		}
		while (tens_count > 0)
		{
			ten *= 10;
			tens_count -= 2;
		}
	}
	else if (n < 1)
	{
		while (n < 1)
		{
			n *= 10;
			tens_count++;
		}
		if (tens_count % 2 == 1)
		{
			n /= 10;
			tens_count--;
		}
		while (tens_count > 0)
		{
			ten /= 10;
			tens_count -= 2;
		}
	}
	//long double x = n,y = -1,k,b,t;
	//while (fabs(x*x-n)>1e-6)
	//{
	//	t = y;
	//	y = x * x - n;
	//	k = 2 * x;
	//	b = y - k * x;
	//	x = -(b / k);
	//}
	//return x*ten;
	long double l = 0, r = (n>=1 ? n:1), mid=0;
	while (fabs(mid * mid - n)>1e-8)
	{
		mid = (l + r) / 2;
		if (mid * mid > n) r = mid;
		else l = mid;
	}
	return l*ten;
}

相关推荐,log的实现方法

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服