一个正整数 n 是斐波那契数当且仅当 5×n²+4 或 5×n²−4 至少一个是完全平方数;需两者都检查,注意 n=0 的负值处理及浮点开方精度问题。

用数学性质快速判断:检查 5×n²±4 是否为完全平方数
判断一个正整数 n 是否为斐波那契数,最高效的方法不是生成序列再查找,而是利用一个经典数学结论:一个正整数 n 是斐波那契数,当且仅当 5 * n * n + 4 或 5 * n * n - 4 中至少一个是完全平方数。
这个性质来自比内公式(Binet’s formula)的逆向推导,时间复杂度是 O(1),远优于遍历或递归生成。
实操注意点:
- 必须对两个值都检查:
5 * n * n + 4和5 * n * n - 4,只查一个会漏判(比如n = 1时,5*1+4=9是平方数,但5*1-4=1也是——但n = 2时只有+4成立) - 计算前要确保
n是非负整数;n = 0是合法斐波那契数(F₀ = 0),此时5*0-4 = -4为负,跳过平方判断即可 - 用
sqrt求整数平方根时,推荐用llround(sqrt(x))再平方验证,避免浮点误差(尤其在大数时sqrt(25)可能返回4.9999999)
手写 is_perfect_square 函数避坑
C++ 标准库没有直接的 is_perfect_square,自己实现时容易在边界和类型上出错。
立即学习“C++免费学习笔记(深入)”;
推荐写法(支持 long long 输入):
bool is_perfect_square(long long x) {
if (x < 0) return false;
if (x == 0 || x == 1) return true;
long long r = llround(sqrt((double)x));
return r * r == x;
}关键细节:
- 输入类型用
long long,防止n较大时5*n*n溢出int - 必须先判断
x ,否则 <code>sqrt传负数会返回NaN,后续比较失效 - 不用
(long long)sqrt(x)强转——截断误差比四舍五入更危险;llround在<cmath>中,需 C++11+ - 最后一定要用
r * r == x验证,不能只信sqrt返回值
完整判断函数与典型错误示例
组合起来就是一个健壮的 is_fibonacci:
bool is_fibonacci(long long n) {
if (n < 0) return false;
long long t1 = 5LL * n * n + 4;
long long t2 = 5LL * n * n - 4;
return is_perfect_square(t1) || is_perfect_square(t2);
}常见误判场景:
-
is_fibonacci(4)→ 返回false(正确,4 不在斐波那契序列中) -
is_fibonacci(1)→ 返回true(正确,F₁ = F₂ = 1) - 若忘记
LL后缀,5 * n * n在n > 46340时对int溢出,结果未定义 - 若没处理
n = 0,t2 = -4传入is_perfect_square会直接返回false,但逻辑上没问题;不过显式处理更清晰
什么情况下不该用这个方法?
这个数学判据在绝大多数场景下足够好,但有两处实际限制:
- 当需要同时返回该数在斐波那契序列中的索引(比如“13 是第 7 个斐波那契数”)时,此法无法提供位置信息,得回退到迭代生成并计数
- 对超大整数(如几百位),
double的精度不足以支撑sqrt正确工作,此时需用高精度开方或改用矩阵/二分搜索法 - 如果只是批量判断少量小整数(比如
n ),预生成一张 <code>set<long long>查表反而更简单、不易出错
真正容易被忽略的是溢出控制和浮点验证——这两个点不加防护,函数在看似正常的数据上就会静默返回错误结果。


















