三角形数是能表示为前k个自然数之和的正整数,即n = k(k+1)/2;判定方法为计算k = (−1 + √(1 + 8n))/2,若k为正整数则n是三角形数,需用round取整并验证平方以避免浮点误差。

什么是三角形数?先看判定公式
一个正整数 n 是三角形数,当且仅当存在某个正整数 k,使得 n = k * (k + 1) / 2。这个公式来自前 k 个自然数之和。直接解这个方程,可得:k = (-1 + sqrt(1 + 8 * n)) / 2。所以判断逻辑就变成:算出这个 k,再验证它是否为正整数。
注意浮点精度问题——sqrt 返回的是 double,直接取整可能出错。稳妥做法是:计算 root = sqrt(1 + 8 * n),检查 root 是否接近整数(比如 abs(root - round(root)) ),再验证 <code>(long long)round(root) 是否为奇数(因为 1 + 8n 必须是完全平方数,且该平方根必须是奇数,才能保证 k 为整数)。
用 sqrt 判定的实操写法
推荐使用 std::sqrt 配合整型校验,避免循环。关键不是“算得快”,而是“不漏判、不错判”:
- 先转成
long long防溢出(n较大时,8 * n可能溢出int) - 计算
disc = 1LL + 8LL * n,再调用std::sqrt(disc) - 取最接近的整数
root = static_cast<long long>(std::round(std::sqrt(disc)))</long> - 验证两个条件:
root * root == disc且(root & 1)(即root是奇数)
示例:isTriangular(10) → disc = 81 → root = 9 → 9*9==81 && (9&1)==true → 是三角形数(k=4)。
迭代法为什么通常不推荐?
从 k = 1 开始累加 k*(k+1)/2 直到 ≥ n,逻辑直观但有明显短板:
- 时间复杂度
O(sqrt(n)),对n = 1e12要循环约1.4e6次,而公式法是O(1) - 容易因整型溢出出错:计算
k*(k+1)/2时,若用int,k超过 46340 就溢出 - 边界处理易错:比如
n = 1时,k应从 1 开始,但循环终止条件写成sum 会漏掉相等情况
除非你明确知道 n 总是很小(比如 ),否则没必要用迭代。
实际编码中容易踩的坑
公式法看着简单,但 C++ 实现时几个细节常导致误判:
-
std::sqrt对long long参数无重载,必须先转成double或long double——但double对大于2^53的整数无法精确表示,所以n > ~1e13时,disc的平方根可能被四舍五入错 - 不要用
floor(sqrt(x))然后验证平方,应统一用round再平方比对,否则sqrt(9999999999999999)可能返回略小于真实值的浮点数 - 忘记检查
root是否为奇数:例如n = 15→disc = 121→root = 11(奇数,ok);但若误用偶数根(如人为构造错误),k就不是整数
超过 1e15 的输入,建议改用整数开方(如二分查找求 sqrt(disc)),否则浮点误差不可控。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











