sqrt需传浮点数,int须显式转换如static_cast(x);负数返回nan,需isnan判断;大整数转double可能精度丢失;求整数平方根应避免sqrt+round,推荐二分查找或向下取整后验证。

用 sqrt 前必须转成浮点数,否则编译失败或结果错误
sqrt 在 C++ 标准库中只接受浮点类型(double、float、long double),不支持 int 直接传入。直接写 sqrt(25) 看似能过,但实际调用的是 sqrt(double) 重载版本——编译器会隐式转换,但容易掩盖精度问题或整型溢出风险。
- 显式转换更安全:
sqrt(static_cast<double>(x))</double> - 若
x是负数,sqrt返回NaN(不是抛异常),后续比较需用std::isnan - 对大整数(如接近
INT_MAX),转double可能丢失精度——double仅保证约 15–17 位十进制有效数字,而int在 32 位系统上最多 10 位,通常够用;但 64 位long long就可能出问题
整数平方根要精确结果?别用 sqrt + round,改用二分查找或 std::sqrt 后向下取整再验证
很多场景要的是「最大的整数 r 满足 r * r 」,即整数平方根(floor of sqrt)。直接 <code>static_cast<int>(round(sqrt(x)))</int> 会因浮点舍入误差翻车——比如 x = 2147395600(= 46340²),某些平台下 sqrt 返回略小于 46340.0 的值,round 变成 46339,再平方就小于原数。
- 稳妥做法:先算
int r = static_cast<int>(std::sqrt(x));</int>,然后检查(r + 1) * (r + 1) ?是则 <code>r++;再检查r * r x - 更干净:用二分查找,范围
[0, x](实际可缩到[0, min(x, 65536)]),无浮点误差,适合嵌入式或要求确定性的场合 - 注意
r * r可能溢出,建议用long long中间计算,尤其当x是int但接近上限时
头文件和命名空间别漏掉:#include <cmath></cmath>,且避免用 using namespace std
没包含 <cmath></cmath>,sqrt 无法识别;在 C++ 中,C 标准库函数(如 sqrt)被放进 std 命名空间,不加 std:: 前缀且没 using 就会报错(取决于编译器严格程度)。
- 推荐写法:
std::sqrt(static_cast<double>(x))</double> - 不推荐
using namespace std:它把整个std拉进来,可能和自定义的sqrt冲突,尤其在大型项目或头文件里 - 有些旧代码写
#include <math.h></math.h>,这是 C 风格,在 C++ 中不保证声明在std中,行为不可靠
性能敏感时,整数平方根优先选位运算或查表,sqrt 不是零成本
std::sqrt 底层调用硬件指令(如 x86 的 sqrtss)或数学库实现,虽快但仍有函数调用开销和浮点运算延迟。对大量小整数(如 0–10000)反复求根,预计算查表反而更快;对单次、任意大小整数,二分查找的常数也极小。
立即学习“C++免费学习笔记(深入)”;
- 查表示例:
static constexpr std::array<int> isqrt_lut = []{ /* 初始化 */ }();</int> - 位运算法(如牛顿迭代整数版)收敛快,但代码稍长,适合不能用浮点单元的环境
- 现代编译器对
sqrt有很好优化,但别假设它比一次整数乘法还快——尤其在循环内频繁调用时,值得压平或缓存
整数平方根真正的麻烦不在调用 sqrt 这一行,而在边界条件:负输入、大数溢出、浮点舍入、类型隐式转换链。这些地方一松懈,测试用例跑得过,线上数据一来就错。








