算法竞赛避坑指南-明明逻辑对了却全WA?警惕C++的两个致命精度陷阱
算法竞赛避坑指南-明明逻辑对了却全WA?警惕C++的两个致命“精度陷阱”
在刷题和打比赛时,很多人经常遇到一种令人崩溃的情况:算法思路完全正确,自己造的样例也过了,一交上去却满屏 WA(答案错误)。
这往往不是你的逻辑出了问题,而是你不知不觉踩进了 C++ 底层处理浮点数(小数)的“精度陷阱”。本文将拆解两个最高频的踩坑场景,并给出能保命的标准代码模板。
陷阱一:用 pow 提取数字的每一位
很多新手在需要提取一个数字的各个数位时,喜欢用数学思维,通过 pow 函数构造 10、100、1000 这样的基数:
C++
1 | // 典型的错误写法 |
为什么会死得很难看?
pow 函数的返回值是浮点数 (double)。在计算机底层的二进制换算中,pow(10, 2) 的结果不一定是完美的 100,它很可能被表示为 99.999999999。
当你在它前面加上 (long long) 进行强制类型转换时,C++ 的机制是无情地向下截断,直接砍掉所有小数部分,它绝对不会帮你四舍五入。于是,99.9999999 瞬间变成了 99。你的取模和除法基数全乱了,提取出来的数字自然错得离谱。
🌟 正确解法
别再用带有小数的函数做纯整数操作了。提取数位请使用以下两种方法:
方法 A:转成字符串(最省心、防越界)
直接将数字转为文本,想取哪位取哪位,从左往右遍历极度舒适。
C++
1 | string s = to_string(n); |
方法 B:纯数学取模(速度最快)
利用 % 10 取最后一位,/ 10 删最后一位,从右向左依次剥离。纯整数运算,零精度损失。
C++
1 | long long temp = n; |
陷阱二:用 pow 和 sqrt 判别完全平方数
判断一个数是不是完全平方数,最直觉但也最危险的写法就是:开个根号,再平方回去,看看等不等于原数。
C++
1 | // 典型的错误写法 |
为什么会产生大量漏网之鱼?
和上一个坑一样,sqrt 计算出的结果存在极微小的误差。
假设我们验算 10(它显然不是完全平方数,程序应该判定为 false)。
sqrt(10)大约等于 3.16227。pow(3.16227, 2)平方回去时,计算机算出的结果可能是 10.000000000000002。- 经过
(long long)强转后,小数部分被截断,变成了完美的 10。
结果程序判定 10 == 10 成立,直接把不是完全平方数的数字当成完全平方数放行了,导致大面积 WA。
🌟 正确解法
判断完全平方数的核心安全原则是:用系统库求出根号 $\rightarrow$ 变成干净的整数 $\rightarrow$ 用纯整数自己乘自己来验算。
为了应对算法题里动辄 $10^{18}$ 级别的大数,防止 2.99999 被截断成 2,必须配合 round 四舍五入。请直接背诵以下模板:
C++
1 | #include <cmath> |
总结
在算法竞赛中,请牢记一条铁律:能用整数解决的问题,绝对不要碰带有小数的函数。浮点数天生带有误差,一旦混用 pow、sqrt 等函数而不加处理,就是在拿你的 AC 率碰运气。掌握纯整数运算和精确的转换模板,才能彻底告别“玄学 WA”。






