为啥我们要检查素数的平方根以确定它是不是为素数?
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*b
和a <= 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
不是素数,它可以分解为两个因式a
和b
:
n = a * b
现在a
和b
不能都大于n
的平方根,从那时起乘积a * b
将大于sqrt(n) * sqrt(n) = n
。所以在n
的任何因式分解中,至少有一个因式必须小于n
的平方根,如果找不到任何小于或等于平方根的因式,n
必须是一个素数。
【讨论】:
鉴于我们使用的是浮点数,sqrt(n)
如何必须足够精确才能保持该属性。
@Benoît 如果您想避免浮点数的复杂性,您始终可以使用检查 i * i <= n
而不是 i <= sqrt(n)
。
因为它不会伤害(除了有时额外的除法)来检查一个除数,你可以只计算 ceil(sqrt(n))。
@gnasher729 在某些情况下这可能有用,但这在很大程度上取决于实现细节(编程语言、硬件、数据类型、库),在一般考虑中,这些细节都不为人所知。跨度>
溢出除外。 :) i <= 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
是实数,而 n
、a
和 b
是自然数。
现在可能有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 的回答既简洁又不会在此过程中产生更多问题。
我回滚到上一个好的版本。当有人不必要地删除了流程所需的单词(“因此”)时,您错过了它。
我比接受的答案更喜欢这个答案 - 接受的答案并不能很好地解释为什么 a
和 b
都不能大于 sqrt(n)
。 3 个案例让我明白了。【参考方案7】:
任何合数都是素数的乘积。
假设n = p1 * p2
,其中p2 > p1
是质数。
如果n % p1 === 0
则n 是一个合数。
如果n % p2 === 0
也猜猜n % p1 === 0
是什么!
所以没有办法同时使用n % p2 === 0
而是n % p1 !== 0
。
换句话说,如果一个合数 n 可以被除以
p2,p3...pi(它的较大因数)它也必须除以它的最低因数p1。
事实证明,最低的因素p1 <= Math.square(n)
总是正确的。
【讨论】:
如果你好奇 为什么 这是真的@LoMaPh 在它的回答中很好地解释了这个事实。我添加了我的答案,因为我很难想象和理解其他提供的答案。它只是没有点击。 伙伴我真的相信这是正确的答案。每个人都说 a=b*c,但他们没有提到 b 和 c 是素数。所以我试图找出答案,正如你所说,没有点击。直到我找到你的答案,让一切都清楚!非常感谢你做的这些!否则,一整天我脑子里都会有这个问题!【参考方案8】:假设给定的整数 N
不是素数,
然后 N 可以分解为两个因子 a
和 b
, 2 <= a, b < N
使得 N = a*b
。
显然,它们不能同时大于sqrt(N)
。
让我们不失一般性地假设a
更小。
现在,如果您在[2, sqrt(N)]
范围内找不到任何N
的除数,那是什么意思?
这意味着N
在[2, a]
中没有任何除数作为a <= sqrt(N)
。
因此,a = 1
和 b = n
,因此 根据定义,N
是素数。
...
如果您不满意,请继续阅读:
(a, b)
的许多不同组合都是可能的。假设他们是:
(a1, b1), (a2, b2), (a3, b3), ..... , (ak, bk)。不失一般性,假设 aii, 1<= i <=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)。所以有a
和b
这样的数字
n = ab (1 < a <= b < n)
通过将关系a<=b
乘以a
和b
,我们得到:
a^2 <= ab
ab <= b^2
因此:(注意n=ab
)
a^2 <= n <= b^2
因此:(注意a
和b
是正数)
a <= sqrt(n) <= b
因此,如果一个数(大于 1)不是质数,并且我们测试该数的平方根的可除性,我们会找到其中一个因数。
【讨论】:
【参考方案13】:因为如果一个因子大于 n 的平方根,那么与它相乘等于 n 的另一个因子必然小于 n 的平方根。
【讨论】:
以上是关于为啥我们要检查素数的平方根以确定它是不是为素数?的主要内容,如果未能解决你的问题,请参考以下文章