为啥我们要检查素数的平方根以确定它是不是为素数?

Posted

技术标签:

【中文标题】为啥我们要检查素数的平方根以确定它是不是为素数?【英文标题】:Why do we check up to the square root of a prime number to determine if it is prime?为什么我们要检查素数的平方根以确定它是否为素数? 【发布时间】:2011-08-14 05:54:38 【问题描述】:

要测试一个数是否是素数,为什么我们必须测试它是否只能被该数的平方根整除?

【问题讨论】:

因为如果n = a*ba <= b 然后a*a <= a*b = n 澄清一下,这意味着我们只需要测试到floor(sqrt(n)) mathandmultimedia.com/2012/06/02/… 【参考方案1】:

设 n 为非质数。因此,它至少有两个大于 1 的整数因子。设 f 是 n 的这些因子中的最小值。假设 f > sqrt n。那么 n/f 是一个整数 ≤ sqrt n,因此小于 f。因此,f 不可能是 n 的最小因子。减少荒谬; n 的最小因数必须≤ sqrt n。

【讨论】:

举个例子解释一下,这个完全看不懂【参考方案2】:

是的,正如上面正确解释的那样,迭代到 Math.floor 一个数字的平方根来检查它的素数就足够了(因为sqrt 涵盖了所有可能的除法情况;Math.floor,因为任何整数以上sqrt 已经超出了它的范围)。

这是一个可运行的 javascript 代码 sn-p,它代表了这种方法的一个简单实现——它的“运行时友好性”足以处理相当大的数字(我尝试检查素数和不是最高 10**12 的素数,即 1 万亿,将结果与online database of prime numbers 进行比较,即使在我的廉价手机上也没有遇到错误或滞后):

function isPrime(num) 
  if (num % 2 === 0 || num < 3 || !Number.isSafeInteger(num)) 
    return num === 2;
   else 
    const sqrt = Math.floor(Math.sqrt(num));
    for (let i = 3; i <= sqrt; i += 2) 
      if (num % i === 0) return false;
    
    return true;
  
<label for="inp">Enter a number and click "Check!":</label><br>
<input type="number" id="inp"></input>
<button onclick="alert(isPrime(+document.getElementById('inp').value) ? 'Prime' : 'Not prime')" type="button">Check!</button>

【讨论】:

【参考方案3】:

如果一个数n不是素数,它可以分解为两个因式ab

n = a * b

现在ab 不能都大于n 的平方根,从那时起乘积a * b 将大于sqrt(n) * sqrt(n) = n。所以在n的任何因式分解中,至少有一个因式必须小于n的平方根,如果找不到任何小于或等于平方根的因式,n必须是一个素数。

【讨论】:

鉴于我们使用的是浮点数,sqrt(n) 如何必须足够精确才能保持该属性。 @Benoît 如果您想避免浮点数的复杂性,您始终可以使用检查 i * i &lt;= n 而不是 i &lt;= sqrt(n) 因为它不会伤害(除了有时额外的除法)来检查一个除数,你可以只计算 ceil(sqrt(n))。 @gnasher729 在某些情况下这可能有用,但这在很大程度上取决于实现细节(编程语言、硬件、数据类型、库),在一般考虑中,这些细节都不为人所知。跨度> 溢出除外。 :) i &lt;= n / i 可能没有这个问题。【参考方案4】:

假设我们有一个数字“a”,它不是素数[不是素数/复合数意味着 - 一个可以被除 1 或它本身以外的数字整除的数字。例如,6 可以除以 2,或除以 3,也可以除以 1 或 6]。

6 = 1 × 6 或 6 = 2 × 3

所以现在如果“a”不是素数,那么它可以除以另外两个数字,假设这些数字是“b”和“c”。这意味着

a=b*c。

现在如果 "b" 或 "c" ,它们中的任何一个都大于 "a" 的平方根,而不是 "b" 和 "c" 的乘积将大于 "a"。

因此,“b”或“c”总是

由于上述原因,当我们测试一个数是否为素数时,我们只检查直到该数的平方根。

【讨论】:

b & c c. 感谢哥们的指正。做修正。 :)【参考方案5】:

给定任意数n,那么求其因数的一种方法是求其平方根p

sqrt(n) = p

当然,如果我们将 p 自身相乘,那么我们将返回 n

p*p = n

可以改写为:

a*b = n

在哪里p = a = b。如果a 增加,则b 减少以维持a*b = n。所以p是上限。

更新:我今天又重新阅读了这个答案,它对我来说变得更清楚了。 p 的值不一定是整数,因为如果是整数,那么 n 就不是素数。因此,p 可能是一个实数(即,带有分数)。而不是遍历n 的整个范围,现在我们只需要遍历p 的整个范围。另一个p 是镜像副本,因此实际上我们将范围减半。然后,现在我看到我们实际上可以继续重新执行 square root 并将其执行到 p 以进一步扩大一半范围。

【讨论】:

【参考方案6】:

假设m = sqrt(n) 然后m × m = n。现在如果n 不是素数,那么n 可以写成n = a × b,所以m × m = a × b。请注意,m 是实数,而 nab 是自然数。

现在可能有3种情况:

    a > m ⇒ b a = m ⇒ b = m a m

在所有 3 种情况下,min(a, b) ≤ m。因此,如果我们搜索到m,我们肯定会找到n 的至少一个因子,这足以证明n 不是素数。

【讨论】:

n = 12 m = sqrt(12) = 3.46, a = 2, b = 6. n = mm 即 12=3.46*3.46 和 n = ab即12=2*6。现在条件 3. a 我认为我们应该首先强调这个假设。假设n is not a prime,并证明它,否则它是素数。 实际上,我不相信这是一个更好的答案。这是一个正确的答案,但它并没有真正回答这个问题。它只是描述了围绕素数和 sqrt 的其他一些动态。 @Sven 的回答既简洁又不会在此过程中产生更多问题。 我回滚到上一个好的版本。当有人不必要地删除了流程所需的单词(“因此”)时,您错过了它。 我比接受的答案更喜欢这个答案 - 接受的答案并不能很好地解释为什么 ab 都不能大于 sqrt(n)。 3 个案例让我明白了。【参考方案7】:

任何合数都是素数的乘积。

假设n = p1 * p2,其中p2 &gt; p1 是质数。

如果n % p1 === 0n 是一个合数。

如果n % p2 === 0 也猜猜n % p1 === 0 是什么!

所以没有办法同时使用n % p2 === 0 而是n % p1 !== 0。 换句话说,如果一个合数 n 可以被除以 p2,p3...pi(它的较大因数)它也必须除以它的最低因数p1。 事实证明,最低的因素p1 &lt;= Math.square(n) 总是正确的。

【讨论】:

如果你好奇 为什么 这是真的@LoMaPh 在它的回答中很好地解释了这个事实。我添加了我的答案,因为我很难想象和理解其他提供的答案。它只是没有点击。 伙伴我真的相信这是正确的答案。每个人都说 a=b*c,但他们没有提到 b 和 c 是素数。所以我试图找出答案,正如你所说,没有点击。直到我找到你的答案,让一切都清楚!非常感谢你做的这些!否则,一整天我脑子里都会有这个问题!【参考方案8】:

假设给定的整数 N 不是素数,

然后 N 可以分解为两个因子 ab2 &lt;= a, b &lt; N 使得 N = a*b。 显然,它们不能同时大于sqrt(N)

让我们不失一般性地假设a 更小。

现在,如果您在[2, sqrt(N)] 范围内找不到任何N 的除数,那是什么意思?

这意味着N[2, a] 中没有任何除数作为a &lt;= sqrt(N)

因此,a = 1b = n,因此 根据定义,N 是素数

...

如果您不满意,请继续阅读:

(a, b) 的许多不同组合都是可能的。假设他们是:

(a1, b1), (a2, b2), (a3, b3), ..... , (ak, bk)。不失一般性,假设 aii, 1&lt;= i &lt;=k.

现在,为了能够证明N 不是质数,证明没有任何一个i 可以被进一步分解就足够了。而且我们还知道 aisqrt(N),因此您需要检查直到 sqrt(N),这将涵盖所有 ai。因此,您将能够得出N 是否为素数的结论。

...

【讨论】:

【参考方案9】:

要测试一个数字的素数,n,首先需要一个循环,如下所示:

bool isPrime = true;
for(int i = 2; i < n; i++)
    if(n%i == 0)
        isPrime = false;
        break;
    

上述循环的作用是:对于给定的 1 ,它检查 n/i 是否为整数(余数为 0)。如果存在一个 n/i 是整数的 i,那么我们可以确定 n 不是质数,此时循环终止。如果没有 i,n/i 是整数,则 n 是素数。

对于每个算法,我们都会问:我们能做得更好吗?

让我们看看上面的循环中发生了什么。

i 的序列:i = 2, 3, 4, ... , n-1

整数检查的顺序是:j = n/i,即 n/2, n/3, n/4, ... , n/(n-1)

如果对于某些 i = a,n/a 是一个整数,那么 n/a = k (integer)

或n = ak,显然n > k > 1(如果k = 1,则a = n,但i永远不会达到n;如果k = n,则a = 1,但i从2开始)

另外,n/k = a,如上所述,a 是 i 的值,所以 n > a > 1。

所以,a 和 k 都是 1 和 n 之间的整数(不包括)。因为,i 达到了该范围内的每个整数,在某个迭代 i = a,而在另一个迭代 i = k。如果 n 的素数测试对 min(a,k) 失败,它也会对 max(a,k) 失败。所以我们只需要检查这两种情况之一,除非 min(a,k) = max(a,k) (其中两个检查减少为一个)即 a = k ,此时 a*a = n,意味着 a = sqrt(n)。

换句话说,如果对于某些 i >= sqrt(n)(即 max(a,k)),n 的素性检验失败,那么对于某些 i

【讨论】:

在 cmets 和 6 岁的答案中有更短且恕我直言更容易理解和更多的主题解释......【参考方案10】:

所以要检查一个数 N 是否是素数。 我们只需要检查 N 是否可以被数字整除Y N

因此一个因子必须小于或等于 SQROOT(N) (而另一个因子大于或等于 SQROOT(N) )。 因此,要检查 N 是否为素数,我们只需要检查这些数字

【讨论】:

【参考方案11】:

这只是因式分解和平方根的基本用途。

它可能看起来很抽象,但实际上它只是在于非质数的最大可能阶乘必须是它的平方根,因为:

sqrroot(n) * sqrroot(n) = n.

鉴于,如果任何大于 1 和小于或大于 sqrroot(n) 的整数均分为 n,那么n不能是素数。

伪代码示例:

i = 2;

is_prime = true;

while loop (i <= sqrroot(n))

  if (n % i == 0)
  
    is_prime = false;
    exit while;
  
  ++i;

【讨论】:

出色的观察。使用这个观察结果在 Swift 中创建一个 guard 语句以及这个方便的 ***.com/a/25555762/4475605 来提前退出计算而不是浪费计算能力。感谢您发帖。 @Adrian 我必须承认,在回到这个答案之后,我确实在您发帖时发现了一个错误。您不能对 0 执行除法,理论上如果可以,++i 将成为数字 1,这将始终返回 false(因为 1 可以除以一切)。我已经更正了上面的答案。 是的...我在我的代码中解决了这个问题...您的平方根观察是在开始运行计算之前尽早抛出非质数的好方法。我被一个大数字杀死了,结果证明这是浪费时间。我还了解到这种算法也可以大大减少大数字的处理时间。 en.wikipedia.org/wiki/Miller–Rabin_primality_test【参考方案12】:

假设n 不是质数(大于1)。所以有ab这样的数字

n = ab      (1 < a <= b < n)

通过将关系a&lt;=b 乘以ab,我们得到:

a^2 <= ab
 ab <= b^2

因此:(注意n=ab

a^2 <= n <= b^2

因此:(注意ab 是正数)

a <= sqrt(n) <= b

因此,如果一个数(大于 1)不是质数,并且我们测试该数的平方根的可除性,我们会找到其中一个因数。

【讨论】:

【参考方案13】:

因为如果一个因子大于 n 的平方根,那么与它相乘等于 n 的另一个因子必然小于 n 的平方根。

【讨论】:

以上是关于为啥我们要检查素数的平方根以确定它是不是为素数?的主要内容,如果未能解决你的问题,请参考以下文章

c语言求1-1000素数的算法问题

是否有一个简单的算法可以确定 X 是否为素数?

C语言中如何判断一个数是完全平方数

c语言怎么判断一个数是素数

使用BitArray判断素数

为啥哈希表的大小为 127(素数)优于 128?