当您使用最后一个值 (curr) 来确定下一个范围时,您正在以指数方式增加范围。平均而言,随机素数应该落在范围的中间,范围从 X 到 2X。这将在每次迭代时将范围向前移动大约 1.5 倍。通过 10,000 次迭代,您的范围将增加多达 1.5^10000 (2^5850) 倍,这很快就会使即使 sympy 也很难产生素数。
如果您的目标只是在第 i 个和第 (i+1) 个素数之间有足够数量的不同位,您可以保持相同的数量级并过滤与前一个素数的最少数量的不同位(而不是增加随机范围的大小)。
例如:
def oneBits(N): return N%2 + oneBits(N//2) if N else 0
minDiff = 25 # minimum number of differing bits from ith to (i+1)th
minValue = 2**50
maxValue = minValue*2-1
primes = [randprime(minValue,maxValue)]
count = 10000
for _ in range(count-1):
while True:
p = randprime(minValue,maxValue)
if oneBits(primes[-1]^p)>=minDiff: break
primes.append(p)
请注意,我没有 sympy,所以我使用纯随机数进行了一些不同的测试,我得到了下一个素数:
内存高效素数生成器:
def genPrimes(toN):
skips = dict()
maxSkip = int(toN**0.5)
if toN>=2: yield 2
for p in range(3,toN+1,2):
if p not in skips:
yield p
if p <= maxSkip: skips[p*p] = 2*p
else:
stride = skips.pop(p)
multiple = p + stride
while multiple in skips: multiple += stride
skips[multiple] = stride
从 N 中获取下一个素数的函数:
primes = list(genPrimes(2**26)) # for 2^50 max base prime is √(2^51) ~ 2^26
def nextPrime(N):
sieve = [1]*N.bit_length()*20
maxPrime = int((N+len(sieve))**0.5)
for p in primes:
if p>maxPrime: break
offset = (p-N%p)%p
if offset>len(sieve): continue
sieve[offset::p] = [0]*len(range(offset,len(sieve),p))
for p,isPrime in enumerate(sieve,N):
if isPrime: return p
return nextPrime(N+len(sieve))
最小间隔的 50 位素数(生成器):
import random
def randomPrimes(count,bits=50):
minVal = 2**bits
maxVal = minVal*2-1
minDiff = bits//2
prevPrime = 0
def oneBits(N): return N%2 + oneBits(N//2) if N else 0
for _ in range(count):
while True:
n = random.randint(minVal,maxVal)
if prevPrime and oneBits(prevPrime^n)<minDiff: continue
n = nextPrime(n)
if not prevPrime: break
if oneBits(prevPrime^n)>=minDiff: break
yield n
输出:
for p in randomPrimes(10000):
print(p,f"{p:b}")
2071968049418461 111010111000111000110100111100100100101000011011101
1399795190350597 100111110010001101100110111000101000100001100000101
1530818178259709 101011100000100010101100001101110110001101011111101
1140103670657957 100000011001110101100010010010010111111001110100101
1911908333932859 110110010101101111011011001000101100101000100111011
1236033889571977 100011001000010101010010000111010110001010010001001
1752989992684999 110001110100101010111001001110011110000110111000111
1849449158362859 110100100100001000001110000000111010100011011101011
1349704431776567 100110010111000110010001101001101010011001100110111
1142235147712271 100000011101101101101011000001110101011011100001111
...
每次迭代大约需要 0.5 秒(无论进行了多少次迭代)。我相信 sympy 应该比我的自制函数快得多。