Java使用Long类型for循环无限循环问题排查(欧拉项目习题)
问题原因
你遇到的"无限循环"和Long类型本身没有关系,是代码里的4个逻辑/类型错误共同导致的:
- 变量引用错误:定义了待计算的目标值
long number = 600851475143L,但循环取模判断时用的是无关的测试变量int temp = 15,全程没有对目标数做计算。 - 类型溢出触发死循环:
isPrime方法的循环变量用的是int类型,当传入的待判断值超过Integer.MAX_VALUE(2147483647)时,int类型的i自增到最大值后会溢出为负数,永远满足i < number(number为正long值)的循环条件,直接触发死循环。 - 算法效率极低:哪怕没有类型错误,从2遍历到600851475143、质数判断从2遍历到待判断值本身的写法,计算量达到万亿级,运行时间长到和无限循环没有区别。
- 类型不匹配:用
ArrayList<Integer>存储质因数,600851475143的质因数可能超过int类型上限,强转(int)i会出现数据溢出错误。
修复方案
- 修正变量引用,删除无用的
temp变量,所有取模判断都针对目标值number执行。 - 统一循环变量类型:所有遍历long类型数值的循环,循环变量都用
long定义,避免int溢出导致循环条件永远成立。 - 优化算法逻辑减少计算量:
- 质数判断不需要遍历到待判断值本身,只需要遍历到该值的平方根即可,因数是成对出现的,超过平方根的部分不需要重复判断。
- 查找质因数时,每次找到一个质因数就把目标数除以该质因数,直到循环结束后剩余的目标值如果大于2,本身就是最大的质因数,不需要遍历完所有小于原目标数的值。
- 把存储质因数的集合、记录最大质因数的变量都改为
long类型,避免int类型溢出。
修复后可直接运行的代码如下:
import java.util.ArrayList; public class LargestPrimeFactor { public static void main(String[] args) { long targetNum = 600851475143L; ArrayList<Long> primeFactors = new ArrayList<>(); long largestPrime = 0; for (long i = 2L; i <= Math.sqrt(targetNum); i++) { // 除尽所有相同的质因数 while (targetNum % i == 0) { primeFactors.add(i); targetNum = targetNum / i; } } // 最后剩余的数如果大于2,本身就是质数,也是最大质因数 if (targetNum > 2) { primeFactors.add(targetNum); } for (Long factor : primeFactors) { if (factor > largestPrime) { largestPrime = factor; } } System.out.println("The largest prime factor of the number 600851475143 is: " + largestPrime); } private static boolean isPrime(long checkNum) { if (checkNum <= 1) { return false; } for (long i = 2; i <= Math.sqrt(checkNum); i++) { if (checkNum % i == 0) { return false; } } return true; } }
代码运行后输出结果为
6857,即该题的正确答案。
注意:Long类型本身不会触发无限循环,所有循环无法终止的问题,本质都是循环变量和边界值类型不匹配导致溢出、或者循环终止条件逻辑错误导致的。只要保证循环变量类型和比较的边界值类型一致,long类型的for循环和int类型没有使用差异。
内容的提问来源于stack exchange,提问作者diggijo
相关产品推荐
相关产品推荐

