怎样用计算机算代数,计算机与代数-如何计算sqrt-方法和实现 - 小黑电脑

0.简介

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

1.二分法

最常见的开根号方法就是二分法,计算

df45e7bb134f2c0aa52c897ea1f13dfc.gif,另

ecbb03cdc765cd9809257bd791b8a5d5.gif,当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.牛顿迭代法

牛顿迭代法通过

cab4579eeca903f730d8be612f644756.gif,来计算

df45e7bb134f2c0aa52c897ea1f13dfc.gif

f9b5868ab1467282d919c3fb428edd00.png

首先找到曲线y上一点,一般取

0c251cbad56cd454a4598681a7166fcb.gif,此时得到点

4be23494d2658e981f58de130ece1506.gif,在A点做切线,与x轴交于点B,这一步主要就是计算从

0c251cbad56cd454a4598681a7166fcb.gif开始,然后下一步A点应该怎么走能接近y=0的位置,从上图中可以看出A点要向B方向走才可以,这里为了方便计算,索性直接取下一个A点以

e69b26bd7922c3f2816a602dbc94ca1d.gif,如下图。

405ca2c7acad8bdee840083b6fcc222d.png

这样一来,B点就逐渐接近y=0的点,经过多次迭代,使得

3b751358624ebccc79b6e7856c9f2d0f.gif,其中

64b83bd90351dc7362ed49dff4453a1a.gif表示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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值