Collatz猜想Python-错误输出超过2万亿(仅限!)

Collatz猜想Python-错误输出超过2万亿(仅限!),python,python-3.x,algorithm,iteration,collatz,Python,Python 3.x,Algorithm,Iteration,Collatz,我已经用Python3编写了一个基本脚本来计算Collatz猜想。它接受一个正整数作为输入,并返回步骤数,直到序列降为1 我的脚本适用于小于~2万亿的任何整数输入,但高于此阈值时,输出太小 例如,以下是一些输入、脚本的输出和实际正确的输出: Integer Input Script Output Correct Output 989,345,275,647 1,348 1,348 1,122,382,791,663

我已经用Python3编写了一个基本脚本来计算Collatz猜想。它接受一个正整数作为输入,并返回步骤数,直到序列降为1

我的脚本适用于小于~2万亿的任何整数输入,但高于此阈值时,输出太小

例如,以下是一些输入、脚本的输出和实际正确的输出:

Integer Input          Script Output     Correct Output
   989,345,275,647        1,348             1,348 
 1,122,382,791,663        1,356             1,356 
 1,444,338,092,271        1,408             1,408 
 1,899,148,184,679        1,411             1,411 
 2,081,751,768,559          385             1,437 
 2,775,669,024,745          388             1,440 
 3,700,892,032,993          391             1,443 
 3,743,559,068,799          497             1,549 `
正确的输出值基于此链接:

对于超过2万亿的输入,我的脚本的输出总是比正确的输出少1052,但我不知道是什么导致了这一点

有人能解释一下什么地方出了问题,以及如何更新/修复脚本,使其对所有输入都能正常工作吗?我认为Python能够毫无问题地接受任意大的数字

谢谢大家!

# Python Code for the Collatz Conjecture
# Rules: Take any integer 'n' and assess:
# If integer is even, divide by 2 (n/2)
# If integer is odd, multiply by 3 and add 1 (3n+1)
# Result: a list of all steps until 'n' goes down to 1

while True:
    print("Please enter a positive integer:")
    n = input("")
    if n == 'q':
        print("Until next time ...\n")
        break
    try:
        n = int(n)
        if n > 0:
            i = 0
            while n > 1:
                if n % 2 == 0:
                    n = int(n/2)
                    i += 1
                else:
                    n = int((3*n)+1)
                    i += 1
            print("# of steps to reach '1' = ", str(i), "\n")
        else:
            print("Sorry, that's not a valid entry. Please try again!\n")
    except ValueError:
        print("Sorry, that's not a valid entry. Please try again!\n")
这一行:

n = int(n/2)
…将
n
转换为浮点,将该浮点除以2,然后通过丢弃小数部分将其转换回整数

对于小于等于2**52的整数,转换为浮点是无损的,但对于任何较大的整数,它必须舍入到最接近的53位数字,这将丢失信息

当然,2万亿远低于浮点精度的
2**53
极限,但从N开始的Collatz序列经常比N高出很多。2万亿左右的许多数字都有超过
2**53
的序列,而低于N的数字很少。甚至有可能一整列从2万亿开始的数字经过
2**53
,但下面没有一个数字。但我不知道如何证明这一点,而不为每一个高达2万亿的数字建立完整的序列。(如果有证据,它可能会严重依赖各种不同条件下猜想的现有部分证据,这些条件高于我的工资等级……)

无论如何,解决方案很简单:您希望使用整数除法:

n = n // 2

下面是一个示例来演示:

>>> n = 2**53 + 3
>>> n
9007199254740995
>>> int(n/2)
4503599627370498
>>> n//2
4503599627370497

要验证代码中是否确实发生了这种情况,请尝试以下操作:

def collatz(n):
    overflow = False
    i = 0
    while n > 1:
        if n > 2**53:
            overflow=True
        if n % 2 == 0:
            n = int(n/2)
            i += 1
        else:
            n = int((3*n)+1)
            i += 1
    return i, overflow

if __name__ == '__main__':
    import sys
    for arg in sys.argv[1:]:
        num = int(arg.replace(',', ''))
        result, overflow = collatz(num)
        print(f'{arg:>30}: {result:10,} {overflow}')
当我运行此命令时:

$ python3 collatz.py 989,345,275,647 1,122,382,791,663 1,444,338,092,271 1,899,148,184,679 2,081,751,768,559 2,775,669,024,745 3,700,892,032,993 3,743,559,068,799
…它给了我:

           989,345,275,647:      1,348 False
         1,122,382,791,663:      1,356 False
         1,444,338,092,271:      1,408 False
         1,899,148,184,679:      1,411 False
         2,081,751,768,559:        385 True
         2,775,669,024,745:        388 True
         3,700,892,032,993:        391 True
         3,743,559,068,799:        497 True
因此,我们通过了
2**53
,在同样的情况下,我们得到了错误的答案

要验证修复,请将
int(n/2)
更改为
n//2

           989,345,275,647:      1,348 False
         1,122,382,791,663:      1,356 False
         1,444,338,092,271:      1,408 False
         1,899,148,184,679:      1,411 False
         2,081,751,768,559:      1,437 True
         2,775,669,024,745:      1,440 True
         3,700,892,032,993:      1,443 True
         3,743,559,068,799:      1,549 True

那么,为什么它总是以相同的数量关闭

嗯,这主要是你碰巧使用的具体数字的巧合

当您通过
3n+1
传递
2**53
时,您将把最后一位或最后两位转换为0,这意味着您通常会切断链的一大部分,并将其替换为1或2个分区。但是很明显,会有一些数字,你最终跳到的链子比正确的要长。事实上,我只花了3次就找到了一个:
3743559068799123
应该需要326个步骤,但需要370个步骤


我怀疑(但再一次,我甚至无法想象如何证明)许多大数字最终会在375左右的相同范围内,随着它们(对数)变大,它们会变短一些。为什么?好吧,你能舍入的数字只有这么多,而且它们中的大多数可能彼此循环,你开始做截断除法。所以,我们假设几乎每个靠近
2**53
的数字的舍入周期长度都超过50位,而万亿范围内的大多数数字在300多个步骤内达到
2**53
范围……那么它们中的大多数将在375左右结束。(当然,这些数字是凭空得出的,但你可以做一个蒙特卡罗模拟,看看它们实际上离现实有多远…

我在检查我的项目euler解决方案,看看类似于
n/=2
的东西。在python 2中,代码应该是正确的,though@RoryDaulton问题是2万亿,而不是200万。但无论哪种方式,从N开始的Collatz序列通常都比N高很多。很多接近2万亿的数字会在这一过程中达到2**53以上,但很少(或者没有),这一点一点也不令人难以置信如果
n
的值高于
2**53
并使用
2081751768559
2_775_669_024_745
的值作为输入,我修改了OPs代码以打印注释,并且注释确实已打印。所以这增加了你答案的可信度+1谢谢@abarnert,这真是个骗局!有趣的是,使用浮点除法时,
2**53
以上的所有输出正好比正确的输出低1052次迭代-四舍五入1减少了很多步骤:)@RonNahshon请参见我的编辑。您可以找到其他示例,其中它删除了不同数量的步骤,可能会少很多步骤,甚至添加了步骤。欢迎使用计算机!:D