必须包含才能使用sqrt(),否则编译失败;它有多个重载版本,负数输入行为未定义,整数开方需校验精度,大数场景建议用整数二分避免浮点误差。

用 sqrt() 前必须包含
直接调用 sqrt() 会编译失败,常见报错是 undefined reference to 'sqrt' 或 'sqrt' was not declared in this scope。这是因为 C++ 标准库把数学函数放在 中,且不自动导入全局命名空间。
正确写法:
#include#include int main() { double x = 16.0; std::cout << sqrt(x) << std::endl; // 输出 4 return 0; }
- 别用
(C 风格头文件),它在 C++ 中虽可能工作,但不保证函数重载和std::命名空间行为 -
sqrt()有多个重载版本:支持double、float、long double;传入整数如int会隐式转为double,但建议显式转类型避免歧义 - 链接时若仍报
undefined reference(尤其在某些 Linux 环境下),需额外加编译选项-lm,例如:g++ main.cpp -lm
sqrt() 对负数输入返回 NaN 或引发域错误
标准规定:当参数 时,sqrt() 的行为是未定义的——实际中多数实现返回 NaN(Not a Number),或在开启浮点异常时抛出 FE_INVALID。
安全做法是提前检查:
立即学习“C++免费学习笔记(深入)”;
double safe_sqrt(double x) {
if (x < 0) {
// 可返回 0、抛异常、或用 std::sqrt(std::complex(x))
throw std::invalid_argument("sqrt of negative number");
}
return sqrt(x);
} - 不要依赖
isnan(sqrt(-1))作主逻辑判断,因为NaN不满足任何比较(nan == nan为 false),需用std::isnan()判断 - 若真需要复数开方,应改用
:std::sqrt(std::complex返回(-4)) (0,2) - 对于整数开方需求(如判断是否为完全平方数),直接用
sqrt()后取整再平方验证更可靠,而非只靠sqrt(n)是否为整数
整数开方常用技巧:用 static_cast(sqrt(n) + 0.5) 不够稳
对 int n 求近似整数根时,有人写 static_cast 四舍五入,但这在大数值下易因浮点精度丢失出错(比如 n = 4503599761588224,sqrt() 可能返回略小于真实整数根的值)。
- 更稳妥的方式是先取
long long root = static_cast,再检查(std::sqrt(n)) root * root n - 若仅需向下取整(floor),
static_cast多数情况可行,但要注意(std::sqrt(n)) sqrt()返回值可能略小于理论值,导致向下取整后少 1;加1e-9补偿比加0.5更合理 - C++20 起可考虑
和std::sqrt配合std::lround,但整数场景仍推荐手动校验
性能与替代方案:手写二分整数开方有时更快
对 unsigned int 或 uint64_t 类型做开方,尤其在嵌入式或高频循环中,调用 sqrt() 可能有函数调用开销和浮点运算延迟;而整数二分只需位运算和比较。
示例(无符号 64 位整数):
uint64_t isqrt(uint64_t n) {
if (n == 0) return 0;
uint64_t lo = 1, hi = n;
while (lo < hi) {
uint64_t mid = lo + (hi - lo + 1) / 2;
if (mid <= n / mid) lo = mid;
else hi = mid - 1;
}
return lo;
}- 该版本避免
mid * mid > n溢出,用除法代替乘法判断 - 比
sqrt()在小整数上未必快,但在确定输入范围、禁止浮点单元、或需精确整数语义时更可控 - 注意:编译器对
sqrt()常做内联优化(尤其-O2),所以实测前别预设“一定慢”
浮点精度、负数处理、整数边界、溢出防护——这些不是附加题,是每次调用 sqrt() 时都在发生的底层事实。









