下面是一道来自2022 CCF CSP-J1的一道阅读程序题。通过分析,我们理解如何用二分法和牛顿法来求整数的平方根。
原来的代码
先看试卷中的代码:
#include<iostream>
using namespace std;
// 假设int为32位有符号整数,输入的n是不超过47000的自然数,k是不超过int表示范围的自然数
int n, k;
int solve1() {
int l = 0, r = n;
while (l <= r) {
int mid = (l + r) / 2;
if (mid * mid <= n)
l = mid + 1;
else
r = mid - 1;
}
return l - 1;
}
double solve2(double x) {
if (x == 0)
return x;
for (int i = 0; i < k; i++)
x = (x+n/x)/2;
return x;
}
int main() {
cin >> n >> k;
double ans = solve2(solve1());
cout << ans << ' ' << (ans * ans == n) << endl;
return 0;
}
代码分析
以下是代码的分析:
-
solve1()
函数:- 这个函数使用二分查找法来找出
n
的整数平方根。 l
和r
是查找范围的左右边界。mid
是中间点,判断mid * mid
是否小于等于n
来决定调整查找范围。- 当
l
小于r
时,不断更新l
和r
,直到找到最大整数l-1
使得(l-1) * (l-1) <= n
。
- 这个函数使用二分查找法来找出
-
solve2(double x)
函数:- 这个函数使用类似牛顿法的方法来近似平方根。
- 初始值
x
是solve1()
计算得到的整数平方根。然后进行k
次迭代,更新x
为(x + n / x) / 2
来逐步逼近真正的平方根。 - 最终返回经过
k
次迭代后的近似值x
。
-
main()
函数:- 读取输入的
n
和k
。 - 使用
solve1()
计算n
的整数平方根,然后用solve2()
来近似这个平方根。 - 输出近似的平方根值,并检查
ans * ans
是否等于n
来验证计算结果的准确性。
- 读取输入的
可能的问题和改进:
-
二分查找中的整数溢出:
- 在二分查找中,如果
n
很大,mid * mid
可能会导致整数溢出。建议使用long long
类型来避免溢出问题。
- 在二分查找中,如果
-
solve2()
的初始猜测:solve2()
使用solve1()
的结果作为初始值。虽然这是一个合理的起点,但对于牛顿法的收敛性,可能需要更精确的初始值或者更多的迭代。
-
solve2()
的精度:k
的值决定了迭代次数,实际中可以根据需要调整迭代次数以获取所需精度。如果k
值过小,可能无法获得足够精确的结果。
-
特殊情况处理:
- 确保处理了特殊情况,比如
n = 0
。虽然你的代码在solve2()
中处理了x = 0
,但在实际应用中,确保所有可能的边界条件都被考虑到是很重要的。
- 确保处理了特殊情况,比如
改进后的代码
以下是AI调整后的代码示例:
#include <iostream>
#include <cmath> // 用于 std::fabs
using namespace std;
int n, k;
int solve1() {
long long l