【发布时间】:2022-01-12 14:31:06
【问题描述】:
tl;dr你如何得到一个非常大的 80 位 BigInt 精确素数,而不是“可能”素数?看来我找到并附在下面的代码只会给你一个“可能的”质数。现在的问题是如何确定它是否是“精确”素数(即不是可能的,而是实际的)?
我被引导到this BigInt "random value between" code 用于生成介于最小值和最大值之间的随机 BigInt,以及 this BigInt prime number test code,我已将其粘贴在下面。然后我添加了一个简单的while 循环来生成一定量级的bigint,并检查素数(在我的情况下,素数也是p ≡ 3 mod 4(prime % 4 === 3):
let i = 0n
while (i < 1000000000n) {
let n = randomBigIntBetween(
1000000000100000000010000000001000000000100000000010000000001000000000n,
10000000001000000000100000000010000000001000000000100000000010000000001000000000n
)
if (isPrime(n) && n % 4n === 3n) {
console.log(String(n))
}
i++
}
function randomBigIntBetween(minInclusive, maxExclusive) {
var maxInclusive = (maxExclusive - minInclusive) - BigInt(1)
var x = BigInt(1)
var y = BigInt(0)
while(true) {
x = x * BigInt(2)
var randomBit = BigInt(Math.random()<0.5 ? 1 : 0)
y = y * BigInt(2) + randomBit
if(x > maxInclusive) {
if (y <= maxInclusive) { return y + minInclusive }
// Rejection
x = x - maxInclusive - BigInt(1)
y = y - maxInclusive - BigInt(1)
}
}
}
// Javascript program Miller-Rabin primality test
// based on JavaScript code found at https://www.geeksforgeeks.org/primality-test-set-3-miller-rabin/
// Utility function to do
// modular exponentiation.
// It returns (x^y) % p
function power(x, y, p)
{
// Initialize result
// (JML- all literal integers converted to use n suffix denoting BigInt)
let res = 1n;
// Update x if it is more than or
// equal to p
x = x % p;
while (y > 0n)
{
// If y is odd, multiply
// x with result
if (y & 1n)
res = (res*x) % p;
// y must be even now
y = y/2n; // (JML- original code used a shift operator, but division is clearer)
x = (x*x) % p;
}
return res;
}
// This function is called
// for all k trials. It returns
// false if n is composite and
// returns false if n is
// probably prime. d is an odd
// number such that d*2<sup>r</sup> = n-1
// for some r >= 1
function millerTest(d, n)
{
// (JML- all literal integers converted to use n suffix denoting BigInt)
// Pick a random number in [2..n-2]
// Corner cases make sure that n > 4
/*
JML- I can't mix the Number returned by Math.random with
operations involving BigInt. The workaround is to create a random integer
with precision 6 and convert it to a BigInt.
*/
const r = BigInt(Math.floor(Math.random() * 100_000))
// JML- now I have to divide by the multiplier used above (BigInt version)
const y = r*(n-2n)/100_000n
let a = 2n + y % (n - 4n);
// Compute a^d % n
let x = power(a, d, n);
if (x == 1n || x == n-1n)
return true;
// Keep squaring x while one
// of the following doesn't
// happen
// (i) d does not reach n-1
// (ii) (x^2) % n is not 1
// (iii) (x^2) % n is not n-1
while (d != n-1n)
{
x = (x * x) % n;
d *= 2n;
if (x == 1n)
return false;
if (x == n-1n)
return true;
}
// Return composite
return false;
}
// It returns false if n is
// composite and returns true if n
// is probably prime. k is an
// input parameter that determines
// accuracy level. Higher value of
// k indicates more accuracy.
function isPrime( n, k=40)
{
// (JML- all literal integers converted to use n suffix denoting BigInt)
// Corner cases
if (n <= 1n || n == 4n) return false;
if (n <= 3n) return true;
// Find r such that n =
// 2^d * r + 1 for some r >= 1
let d = n - 1n;
while (d % 2n == 0n)
d /= 2n;
// Iterate given nber of 'k' times
for (let i = 0; i < k; i++)
if (!millerTest(d, n))
return false;
return true;
}
到目前为止,它为我打印了该范围内的几个素数,或者我认为应该是素数,对吗?我对所涉及的数学或素数的“miller test”知之甚少,无法知道该算法是否真的找到了一个精确的素数,或者正在找到可能的东西是素数。
corresponding blog post 的作者开口说:
米勒-拉宾素数检验是对素数的可靠检验,尽管它只能确定一个数为素数的概率。
(加了重音)
据我所知,这个算法似乎只能让我们走上一段路?我们必须做什么才能建立一个保证是素数的列表?假设我们想要非常大的 BigInt 素数......
实际上,对于我当前的用例,我需要找到 70 到 80 位之间的素数,但我想知道如何找到任意大小数字的素数,如果可能的话,最多 65536 位。
知道“素数正好有两个因数——1 和数本身”,我认为,意味着我们需要以某种方式找到 BigInt 的因数。这导致我here 和this function:
function primeFactors(n){
const factors = []
let divisor = 2n
let i = 0
while (n > 2n) {
if (n % divisor == 0n) {
factors.push(divisor)
n = n / divisor
} else{
divisor++
}
i++
if (i % 100 === 0) {
console.log(i)
}
}
console.log(i)
return factors
}
然后我将它添加到我原来的 while 循环中:
while (true) {
let n = rbigint(
1000000000100000000010000000001000000000100000000010000000001000000000n,
10000000001000000000100000000010000000001000000000100000000010000000001000000000n
)
if (isPrime(n) && n % 4n === 3n) {
const factors = primeFactors(n)
console.log(factors)
console.log(String(n))
}
}
如您所见,我还添加了那些 console.log 语句以调试正在进行的迭代次数,因为调用 primeFactor 被挂起。几秒钟后,我取消了记录22481400 迭代的过程,但似乎没有接近完成,我不确定需要多长时间。试图只记录每 1000 万次迭代,它只是突然消失,永远不会完成。我在300000000 迭代后取消以计算isPrime(n) && n % 4n === 3n 为真的第一个数字的因子。看来我们至少需要 300000000300000000300000000300000000300000000300000000 或一些疯狂的迭代次数才能完成分解......我不知道如何计算这部分,但想知道如何得到素数。
所以问题是,在 JavaScript 中,当定位这些极大的 BigInt 值时,如何获得“精确”质数,而不是“可能”质数?
【问题讨论】:
-
这似乎不是编码问题。这似乎是一道数学题,或许应该在math.stackexchange.com 提问?
-
这绝对是一个编码问题,我真的想在这一秒写下这段代码。
-
我在您的帖子中数了 6 个问号。您提出的问题是:您如何获得一个非常大的 80 位 BigInt 精确素数,而不是“可能的”素数?那么如何确定它是否是“确切的”素数(即不是可能的,而是实际的)? ...应该是素数,对吧?我对所涉及的数学知识了解得不够多…………这个算法似乎只能让我们部分到达那里?我们必须做什么才能建立一个保证是素数的列表?我如何获得“准确”的质数,而不是“可能的”质数...? 没有一个是关于代码的。每一个都与算法的数学有关。
-
我所知道的最快的方法是产生保证素数的波克林顿定理的变体。实际上,用单个 MR 测试剔除非素数然后使用 ECPP 来证明结果的素数可能更快,但是 ECPP 是很多棘手的代码。即便如此,正如@MrSmith42 所说,计算机本身还不够可靠,无法让您 100% 确定结果是素数。
-
感谢您的问题,我想为您提供所需的帮助,但我认为您的问题分为两部分。 1) 设计一种算法,该算法将计算“精确”素数(大约 80 到 65536 位数字),使用的计算量足够少,可以在人的一生中计算出来。 (math.stackexchange) 和 2) 在 JavaScript (stackoverflow) 中编码该算法。看起来你的问题仍然是#1。如何执行循环的 10^53 次迭代不是 JavaScript 问题——以现代计算机的速度执行是不可行的。你仍然需要一个有效的算法。
标签: javascript algorithm primes bigint