一个正整数 n 是三角形数当且仅当 8n+1 是奇数的完全平方数;判定时需用 round(sqrt(8n+1)) 得整数根 r,再验证 r²=8n+1 且 r 为奇数,避免浮点误差导致误判。

什么是三角形数的代数判定公式
一个正整数 n 是三角形数,当且仅当存在正整数 k,使得 n = k * (k + 1) / 2。把这个式子反解,可得判别式:8 * n + 1 必须是完全平方数,且其平方根为奇数(因为 sqrt(8*n+1) 必须是奇整数,才能保证 k = (sqrt(8*n+1) - 1) / 2 是正整数)。
用 sqrt 判定时为什么不能直接比较浮点结果
C++ 的 std::sqrt 返回 double,浮点精度在大整数(如接近 LLONG_MAX)附近会导致误判:比如 sqrt(8*n+1) 可能算出 123456789.9999999 或 123456790.0000001,强制取整会错。
- 正确做法:先算
long long root = round(sqrt(8LL * n + 1)),再验证root * root == 8LL * n + 1 - 必须用
round而非floor或ceil,否则对刚好处在浮点误差边界的数会漏判 -
8LL * n + 1中的LL后缀防止int溢出(n超过约 2.68e8 就会溢出int)
完整可运行的判定函数
以下函数接受 long long 输入,安全覆盖到约 1e18 范围:
bool isTriangular(long long n) {
if (n (disc)));
// 防止 sqrt 返回值略小导致 round 错,多检查 root-1 和 root+1
for (long long r : {root - 1, root, root + 1}) {
if (r >= 0 && r * r == disc) {
return (r & 1) == 1; // r 必须是奇数
}
}
return false;
}
注意:只靠单次 round + 一次乘法验证仍可能因 double 表示范围不足(>2^53)失败,所以加了 ±1 安全区间;对 n > ~1e13,更稳妥的做法是用整数开方(如二分),但日常用 ±1 已覆盖绝大多数场景。
常见误判例子和调试建议
输入 n = 1000000000000(1e12)时,8*n+1 = 8000000000001,其真实平方根是 2828427.12474619... → 2828427,但 double 可能无法精确表示该数,直接 (long long)sqrt(...) 会截断成 2828426,导致判定失败。
- 调试时打印
disc和root值,确认是否接近真实平方根 - 不要用
std::sqrtf(float)——精度太低,sqrtf(8e9+1)就开始出错 - 若需支持超大整数(>1e18),必须换整数开方,
double无法可靠表示所有 64 位整数
代数公式本身很简洁,但落地时浮点误差是唯一真正要绷紧的弦。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











