考虑以下代码:

public static boolean isPrime(int n) {
    for (int i = 2; i * i <= n; i++)
    if (n % i == 0) return false;
    return n > 1;
}

public static int squareOf(int n) {
    int i = 0;
    while (i * i < n)
    i++;

    return i * i == n ? i: -1;
}


由于(46340)(46340)
然后我期望的是,对于大于(46340)*(46340)的数字,isPrime要么不会终止,要么最终会停止,但会给出一些随机答案。

对于每个单个<
为什么会这样?



在squareOf中,我们有i * i
范围[(46 340)^ 2 +1,2147483641]:正确,但以下各项除外:{2147402577、2147465721、2147469348,
2147478505、2147481513、2147481513、2147482825、2147482929、2147483280、2147483536、2147483556、2147483609、2147483620、2147483641}

[2147483642,Integer.MAX_VALUE]:它似乎没有终止。

为什么对许多价值观给出正确答案?

给出错误答案的值有什么特别之处?

为什么对于2147483641之后的值不终止?

最佳答案

问题似乎如下:

理解:满足循环条件n的最后一个int i*i <= n为2147395600。对于n = 2147395600,当i = 46340时,循环终止。对于[2147395601,2147483647](含)之间的所有int,值i*i <= n为true当我达到36340时,因此将继续进行到i = 34341,此时i*i溢出,因此不再有意义。

无法理解:为什么isPrime函数为何在[2147395601,2147483647](包括该间隔)(循环终止条件不再有意义)的间隔中正确区分了88047个整数中的质数和复合数?

首先,重要的是要了解,在循环达到i = 46340之前,已经确定了可疑区间中的每个复合数字。因此,只有对于n的质数,循环才能达到目标值。现在剩下的问题是,为什么函数几乎总是正确地将间隔中的4085个素数识别为素数。答案也相对简单。当i*i溢出时(即i*i在数学上大于i*i时),Integer.MAX_VALUE的结果等同于将i * i的低32位放入“填充”到一个int中。但是,计算n%i永远不会溢出,因此循环永远不会通过该条件退出(因为n必须是素数)。因此,循环将仅由于i*i大于n并正确返回true而退出,否则将根本不会退出而成为无限循环。

现在我们必须说明为什么退出循环,以及在上面的分析中对于n = Integer.MAX_VALUE出了什么问题。我们需要循环退出的是一个i,对于i*ii*i会溢出,使得正方形的低阶32位的32位等于零,其余31位形成一个大于n的整数。那是一个相当狭窄的范围。碰巧的是,恰好有i的值,Integer.MAX_VALUE的溢出恰好在该范围内,从而允许循环退出。 i = 593968971的值适用于所有值,您可以自己进行测试。在该间隔内,所有素数在2147483629以下的值都较小,您可以通过实验找到该值。

Integer.MAX_VALUE是上述声明的例外。原因再次很简单。没有大于i*i > n的正整数,因此循环永远不会通过i退出。但是,当Integer.MAX_VALUE最终命中时,循环将退出,该函数将返回false,因为n%i等于n%n(始终为0)。

09-11 18:08