习题- 二分法/牛顿迭代法 求算术平方根

一道编程题要用二分查找来求平方根,初学者表示黑人问号,这两个东西能放在一起使用吗?后来看了别人的实现,发现被二分查找的名字误导了,其实就是二分法


这个数是“找”出来的,也就是一个一个数的试,每次都计算 x^2 看等不等于 给定值。但是“找”这个过程,不应该是暴力测试所有区间内的数(也不可能完成),而是逐步缩小范围的,也就是二分法。二分法通过足够多的迭代,就可以得到有足够精度的解了。

这个方法同样可以用于求n次方根


下面是二分法实现(开平方):

float my_sqrt_bin(float n) {
	float precision = 1e-4;
	float lo = 0.0;
	float hi = n;
	float mid = 0.0;
	float delta = 0.0;
	while (1)
	{
		mid = (lo + hi) / 2;
		delta = mid*mid - n;
		if (delta < -precision)lo = mid;
		else if (delta > precision)hi = mid;
		else return mid;
	}
}
时间复杂度:O(logn)

注意:精度最好低于数据类型(float)最大精度一个数量级,否则会由于 (lo+hi)/2 一直等于 lo 而进入死循环



牛顿迭代法用来求解方程近似根,可以用于求解算数平方根,速度比二分法快不少(但受选定的初始点影响):


在我们的这个实例中 f(x)= x^2 -n,f '(x)= 2*x,这里选 x0=n 为初始点:

float my_sqrt_new(float n) {
	float xn = n;
	float f = 0.0;
	float precision = 1e-6;
	while (1)
	{
		xn = xn- (xn*xn - n) / (2 * xn);
		f = xn*xn - n;
		f = f > 0 ? f : -f;
		if (f < precision)return xn;
	}
}


上述是初步实现后的两种不同开方函数,在被开方数比较小(<1033)时,程序正常运行。

当被开方数过大时,float 本身的精度限制就体现出来了,由于整数部分位数增多,原本处在有效数字部分的小数被抛出有效数字区,导致 mid(或 f) 的值一直无法变更,进入死循环。

解决方法有三种:

第一种是把 float 类型改成 double 甚至 long double(虽然不能从根本上解决问题)

第二种是随平方根的整数部分位数增加,逐渐改变精度 precision 来维持比较的有效性。

第三种是手动实现“无限”浮点类型微笑



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值