Collatz猜想Python-错误输出超过2万亿(仅限!)
我已经用Python3编写了一个基本脚本来计算Collatz猜想。它接受一个正整数作为输入,并返回步骤数,直到序列降为1 我的脚本适用于小于~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
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