一个正整数 n 是三角数当且仅当 1 + 8n 是完全平方数且其平方根为奇数;需用 round + 验证 root*root == delta 规避浮点误差,并检查 root 是否为奇数。

三角数的数学判定公式是什么
一个正整数 n 是三角数,当且仅当存在正整数 k,使得 n = k * (k + 1) / 2。把这式子变形,解出 k:两边乘 2 得 2n = k² + k,移项得 k² + k - 2n = 0。这是关于 k 的一元二次方程,判别式为 Δ = 1 + 8 * n。所以 k 有正整数解 ⇔ Δ 是完全平方数,且 sqrt(Δ) 是奇数(因为 k = (-1 + sqrt(Δ)) / 2 必须为正整数)。
用 sqrt 判定是否为完全平方数的坑
C++ 的 std::sqrt 返回 double,浮点误差可能导致误判。比如对大整数(如接近 LLONG_MAX 的值),sqrt(x) 可能略小于真实平方根,取整后错失一个单位。
- 先计算
delta = 1 + 8LL * n(注意用long long防溢出) - 算
root = static_cast<long long>(std::round(std::sqrt(delta)))</long>,比直接floor或cast更稳妥 - 再验证
root * root == delta,而不是只信sqrt的返回值 - 若成立,再检查
(root - 1) % 2 == 0(即root为奇数),才能保证k是正整数
完整可复用的 C++ 函数
以下函数接受 unsigned long long,覆盖常见正整数范围,返回 true 当且仅当输入是三角数:
#include <cmath>
#include <climits><p>bool isTriangular(unsigned long long n) {
if (n == 0) return false; // 正整数前提
unsigned long long delta = 1ULL + 8ULL <em> n;
unsigned long long root = static_cast<unsigned long>(std::round(std::sqrt(static_cast<double>(delta))));
if (root > 3037000499ULL) return false; // sqrt(ULL_MAX) ≈ 4.29e9,但 double 精度在 2^53 后失效;此上限保 double 表达准确
if (root </double></unsigned></em> root != delta) return false;
return (root & 1) == 1; // root 是奇数
}</p></climits></cmath>
注意:root 上限判断是为了规避 double 对超大整数开方失真——当 delta > 2^53 时,double 无法精确表示所有整数,sqrt 结果可能偏差 1。实际项目中若需支持 >1e15 的数,应改用整数二分求平方根。
性能与边界测试要点
该方法时间复杂度 O(1),但浮点运算本身有隐含成本和精度风险。实测易错点包括:
-
n = 1→delta = 9→root = 3→(3-1)/2 = 1,正确 -
n = 1000000000000ULL→delta = 8000000000001ULL,此时double仍能精确表示( - 不检查
root * root == delta直接用sqrt四舍五入结果,会在n = 1806250000000这类数上出错 - 漏判
root奇偶性,会把非三角数如n = 2(delta = 17,非完全平方)之外的某些边缘情况误收
真正麻烦的是大数下的浮点精度——它不报错,只悄悄返回错误结果。写完一定要用已知三角数(如 1, 3, 6, 10, 15, ...)和紧邻非三角数交叉验证。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











