如何用等差数列公式高效解决欧拉计划第1题?结果略有偏差
欧拉计划第1题:等差数列解法的偏差问题分析与修正
你遇到的问题大概率是整数除法的精度丢失或者等差数列公式的计算顺序错误导致的,我们一步步来拆解:
先看你的原始正确实现
这段循环逻辑是没问题的,它遍历0到999的所有数,累加符合条件的3或5的倍数:
public int sumOfMultiplesOf3or5Under1000() { int sum = 0; for (int i = 0; i < 1000; i++) { if (i % 3 == 0 || i % 5 == 0) { sum += i; } } return sum; }
你的等差数列实现的问题点
你的usingAP方法里的项数计算是对的,但sumOfAP函数的计算逻辑存在关键错误:
1. 整数除法的顺序错误
你写的(numberOfTerms / 2) * (2 * ...)会在项数为奇数时丢失精度。比如计算3的倍数和时,项数是333(奇数),333 / 2在Java中会被截断为166,而正确的计算应该是先把所有数相乘,再除以2,避免截断带来的误差。
2. 完整的等差数列公式回顾
等差数列求和的标准公式是:
sum = n * (a₁ + aₙ) / 2
或者等价于 sum = n * (2a₁ + (n-1)d) / 2
其中n是项数,a₁是首项,d是公差,aₙ是末项。
修正后的代码
把sumOfAP的计算顺序调整为先乘后除,就能彻底避免精度丢失问题:
public int usingAP() { // 3的倍数:首项3,公差3,共333项(3*333=999 <1000) // 5的倍数:首项5,公差5,共199项(5*199=995 <1000) // 15的倍数:首项15,公差15,共66项(15*66=990 <1000) return sumOfAP(3, 3, 333) + sumOfAP(5, 5, 199) - sumOfAP(15, 15, 66); } public int sumOfAP(int firstTerm, int commonDifference, int numberOfTerms) { // 先计算n*(2a1 + (n-1)d),再除以2,避免整数截断 return numberOfTerms * (2 * firstTerm + (numberOfTerms - 1) * commonDifference) / 2; }
验证结果
修正后的usingAP方法返回的结果会和原始循环完全一致,都是233168。
另外补充一点:原始循环里包含0,但0对总和没有贡献,所以你的项数计算(从3、5、15开始算项数)是没问题的,不用额外加0的项。
内容的提问来源于stack exchange,提问作者J__




