初学C++笔记——数学运算(一)

这篇博客介绍了如何在C++中不使用内置指数和平方根函数来计算非负整数的算术平方根。文章详细探讨了三种方法:1) 使用指数函数exp()和对数函数ln;2) 通过二分查找法;3) 应用牛顿迭代法。每种方法的实现原理和时间复杂度分析均进行了阐述,特别提到了牛顿迭代法在处理凸函数时的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出非负整数x,范围0 <= x <=,要求在不使用任何内置指数函数和算符(pow(x, 0.5) x ** 0.5)的情况下返回x的算数平方根

思路无非就是1.模拟出指数函数迭代过程得出近似结果2.用其他函数替代平方根函数得到结果

这篇笔记会记录官方答案给出的三种题解

相关代码

🟦使用指数函数exp()和对数函数ln代替平方根函数

    if(x == 0) cout << 0 << endl;
    int ans = exp(0.5 * log(x));
    cout << ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans) << endl
    ;

log()是e为底的对数

log10()是10为底的对数

为什么最后还要比较ans+1和ans,是因为计算机无法存储浮点数的精确值(参考IEEE754)指数函数和对数函数的参数和返回值均为浮点数,因此运算过程中会存在误差。题解中给出了一个例子x=2147395600时,的计算结果和正确值46340相差会导致取整之后得到46339(一般人也不会想到吧喂)

内置的exp()和log()都很快,可以将其时间复杂度视为O(1)

🟦二分查找

还是想找出平方结果小于等于x的数,但是用传统循环时间复杂度是O(n),这里用二分,初始范围设置在0到x之间

    int l = 0, r = x, ans = -1;
    while(l <= r){
        int mid = (r - l) / 2 + l;
        if((long long) mid * mid <= x){
            ans = mid;
            l = mid + 1;
        }
        else r = mid - 1;
    }
    cout << ans << endl;

可以把时间复杂度降到O(logx)

🟦牛顿迭代

将目标x视为C,整个问题能转换成求方程的零点

牛顿迭代实际上是借助泰勒级数,从初始值开始快速逼近,将一个任取的作为初始值,迭代开始

取在函数上的点做一条斜率为该点的导数的直线,和横轴相交于相比于更靠进目标零点。多次迭代,就会得到一个和目标结果及其相近的值

在函数中,那么关于的直线方程可推算为

关联横轴与方程,可以得到的表达式

在进行数次迭代之后,得到的和要求的足够接近

要注意的几点

  1. 初始值的选择

初始的设置为C,因为方程有两个零点,如果选择较小的初始值结果可能会迭代到上,初始的设置为C不仅方便计算还能确保迭代的方向是正确的(你尽管赋值剩下的交给计算机)

  1. 迭代结束的判断条件

一般判断相邻两次迭代的结果差值是否小于一个非负整数可以取值为或者

    double C = x, x0 = x;
    while(1){
        double xi = 0.5*(x0 + C / x0);
        if(fabs(x0 - xi) < 1e-7) break;
        x0 = xi;
    }
    cout << (int)x0 << endl;

时间复杂度同样是O(logx)

小结:

网站分享了三种复杂度低于O(n)的方法,其中牛顿迭代我的收获很大,这只是对凸函数的处理,不知道后面是否能够遇到更合适的应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值