【问题标题】:Fibonacci Sequence: Finding Composites Problem斐波那契数列:寻找复合问题
【发布时间】:2021-08-31 16:41:56
【问题描述】:

我正在寻找 GCD(最大公分母)为 1 的一对数,即序列 X0、X1、... XN 的前 N ​​项都是合数。

对于我的代码,由于某种原因,它在 i == 15、j == 878 和 k == 78 时卡住了。 对列表中的最后两个项目运行 is_prime() 时,它会卡住。

import math


def is_prime(num):
    if num < 2:
        return False
    for x in range(2, math.floor(math.sqrt(num)) + 1):
        if num % x == 0:
            return False
    return True


# create list containing a range of composite numbers
numbers = []
for i in range(4, 200):
    if not is_prime(i):
        numbers.append(i)

for i in numbers:
    found = False
    for j in numbers:
        if math.gcd(i, j) == 1:
            # print(i, "-", j, end=" | ")
            fibonacci = [i, j]
            contains_prime = False
            for k in range(2, 500):
                if is_prime(fibonacci[-2] + fibonacci[-1]):
                    contains_prime = True
                    break
                else:
                    fibonacci = [fibonacci[-1], fibonacci[-2] + fibonacci[-1]]
            if not contains_prime:
                print(i, j)
                found = True
        if found:
            break
    if found:
        break
    if i == numbers[-1]:
        print("No Possibilities Exist.")

【问题讨论】:

  • 卡住了,因为您要检查的数字非常大,而大数字需要真的很长时间才能分解。
  • 也许看看使用更好的主要功能。
  • 试除法是最简单和最弱的素性测试算法,因为对于大数来说是最慢的,你需要更高级的算法,例如 Miller-Rabin 或 Baillie-PSW 素性测试
  • 您的代码在测试 51452069511074530979 是否为质数时卡住了,这是一个用试除法测试的大得离谱的数字(它的平方根是 7173009794)

标签: python fibonacci


【解决方案1】:

正如我在 cmets 中提到的,您需要更好的素性测试算法,这些算法可能难以理解或自行实现,因此您可以使用提供它的库,例如 sympy,只需安装它使用 pip 并将其用作:

import math
from sympy.ntheory import isprime 

# create list containing a range of composite numbers
numbers = []
for i in range(4, 200):
    if not isprime(i):
        numbers.append(i)

for i in numbers:
    found = False
    for j in numbers:
        if math.gcd(i, j) == 1:
            fibonacci = [i, j]
            contains_prime = False
            for k in range(2, 500):
                if isprime(fibonacci[-2] + fibonacci[-1]):
                    contains_prime = True
                    break
                else:
                    fibonacci = [fibonacci[-1], fibonacci[-2] + fibonacci[-1]]
            if not contains_prime:
                print(i, j)
                found = True
        if found:
            break
    if found:
        break
    if i == numbers[-1]:
        print("No Possibilities Exist.")

现在可以快速运行而不会卡住并打印结果:143 142

【讨论】:

  • 它在我的 jupyter-notebook 中完美运行,但是当我在 PyCharm IDE 中运行它时,即使我安装了 sympy,它也无法识别。你知道为什么会这样吗?
  • 如果那些使用自己单独的python安装,这可能是原因,否则不知道
  • 找到了一个临时修复here
【解决方案2】:

问题在于您的 is_prime 函数速度很慢,而不是检查每个数字是否是 for 循环中的素数。为什么不生成一个素数列表,比如说前 100 万个,将它们存储在一个列表中。然后检查你的号码是否是素数,只需检查它是否在列表内。

import math

def gen_prime(n):
    D = {}
    q = 2

    for i in range(n):
        if q not in D:
            yield q
            D[q * q] = [q]

        else:
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]

        q += 1

primes = [i for i in gen_prime(1_000_000)]

def is_prime(num):
    if num in primes:
        return True
    else:
        return False

# create list containing a range of composite numbers
numbers = []
for i in range(4, 200):
    if not is_prime(i):
        numbers.append(i)

for i in numbers:
    found = False
    for j in numbers:
        if math.gcd(i, j) == 1:
            # print(i, "-", j, end=" | ")
            fibonacci = [i, j]
            contains_prime = False
            for k in range(2, 500):
                if is_prime(fibonacci[-2] + fibonacci[-1]):
                    contains_prime = True
                    break
                else:
                    fibonacci = [fibonacci[-1], fibonacci[-2] + fibonacci[-1]]
            if not contains_prime:
                print(i, j)
                found = True
        if found:
            break
    if found:
        break
    if i == numbers[-1]:
        print("No Possibilities Exist.")

运行此代码时,我得到了结果

18 187
>>> 

编辑: 我决定对素数算法进行一些研究,我遇到了 Miller-Rabin。

米勒-拉宾素性检验或拉宾-米勒素性检验是一种 概率素性检验:一种算法,它确定是否 给定数可能是素数,类似于费马素数 检验和 Solovay-Strassen 素性检验。

更多信息请访问Wikipedia。

import random, math

# miller_rabin algorithm
def is_prime(n, k = 40):
    if n == 2:
        return True

    if n % 2 == 0:
        return False

    r, s = 0, n - 1
    while s % 2 == 0:
        r += 1
        s //= 2

    for i in range(k):
        a = random.randrange(2, n - 1)
        x = pow(a, s, n)
        if x == 1 or x == n - 1:
            continue

        for i in range(r - 1):
            x = pow(x, 2, n)
            if x == n - 1:
                break

        else:
            return False

    return True

# create list containing a range of composite numbers
numbers = []
for i in range(4, 200):
    if not is_prime(i):
        numbers.append(i)

for i in numbers:
    found = False
    for j in numbers:
        if math.gcd(i, j) == 1:
            # print(i, "-", j, end=" | ")
            fibonacci = [i, j]
            contains_prime = False
            for k in range(2, 500):
                if is_prime(fibonacci[-2] + fibonacci[-1]):
                    contains_prime = True
                    break
                else:
                    fibonacci = [fibonacci[-1], fibonacci[-2] + fibonacci[-1]]
            if not contains_prime:
                print(i, j)
                found = True
        if found:
            break
    if found:
        break
    if i == numbers[-1]:
        print("No Possibilities Exist.")

这是完整的代码,你可以看到它在运行时返回结果

143 142
>>> 

【讨论】:

  • 代码最终会要求显着大于10**6 的数字的素数,您的素数测试函数将给出假阳性/假阴性
  • 只需增加计数器primes = [i for i in gen_prime(1_000_000)] 而不是一百万放十亿等gen_prime(1_000_000_000) 或者你想增加多少数字。将素数存储在 RAM 中是一种更快的解决方案,然后使用 OP 的原始代码循环并单独检查每个数字。
  • 它测试的数字之一是 51452069511074530979,生成并存储直到该数字 (10**20) 的所有素数,以正确测试它对我来说不是一个好主意...跨度>
  • @Copperfield 我用更好的解决方案更新了我的答案。
  • 看起来不错。我个人更喜欢确定性版本
猜你喜欢
  • 2016-11-28
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 1970-01-01
  • 2010-11-24
  • 2015-06-05
相关资源
最近更新 更多