python 中可能出现整数溢出
Possible integer overflow in python
我正在完成 hackerrank 的项目欧拉问题 #1。
我写了一个蛮力解决方案来检查我的答案。它似乎是正确的,除了 10^9 的输入。
有人告诉我正确答案是:
233333333166666668
我回来了:
233333333166666680
n = 1000000000
sum_of_multiples_3 = int((int((n-1)/3.0)+1) * (int((n-1)/3.0)/2.0) * 3)
sum_of_multiples_5 = int((int((n-1)/5.0)+1) * (int((n-1)/5.0)/2.0) * 5)
sum_of_multiples_15 = int((int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15)
print(sum_of_multiples_3 + sum_of_multiples_5 - sum_of_multiples_15)
您正在使用整数除法的浮点除法:
int((n-1)/3.0)
更好地表示为
(n-1)//3
例如使用 Python 的 floor 除法运算符,不要使用浮点数,然后 floor.
使用整数底除法不会 运行 出现舍入问题,因为您将浮点运算扩展到超出其限制。
当您将 n
推得足够大时,您会看到此舍入错误:
>>> n = 100000000
>>> int((int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15)
333333316666665
>>> ((n-1)//15+1) * ((n-1)//15//2) * 15
333333316666665
>>> n = 1000000000
>>> int((int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15)
33333333166666664
>>> ((n-1)//15+1) * ((n-1)//15//2) * 15
33333333166666665
额外的 1 纯粹是因为您 运行 进入了浮点数的限制:
>>> (int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0)
2222222211111111.0
>>> ((n-1)//15+1) * ((n-1)//15//2)
2222222211111111
>>> (int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15
3.3333333166666664e+16
我不知道你为什么一直从 n
中减去一个;这根本不需要,并会导致不正确的结果。也许您正在尝试补偿浮点数舍入错误?正确的公式是:
(((n // 3) + 1) * (n // 3)) // 2 * 3
(((n // 5) + 1) * (n // 5)) // 2 * 5
(((n // 15) + 1) * (n // 15)) // 2 * 15
给我任何 n
:
的正确输出
>>> n = 1000000000
>>> sum_of_multiples_3 = (((n // 3) + 1) * (n // 3)) // 2 * 3
>>> sum_of_multiples_5 = (((n // 5) + 1) * (n // 5)) // 2 * 5
>>> sum_of_multiples_15 = (((n // 15) + 1) * (n // 15)) // 2 * 15
>>> sum_of_multiples_3 + sum_of_multiples_5 - sum_of_multiples_15
233333334166666668
我会在这里使用一个函数来计算倍数:
def sum_of_multiples(n, k):
k_in_n = n // k
return ((k_in_n + 1) * k_in_n) // 2 * k
因此您可以通过与暴力求和进行比较来验证它是否有效:
>>> sum(range(0, 10000 + 1, 3)) == sum_of_multiples(10000, 3)
True
>>> sum(range(0, 10000 + 1, 5)) == sum_of_multiples(10000, 5)
True
>>> sum(range(0, 10000 + 1, 15)) == sum_of_multiples(10000, 15)
True
然后用它来计算答案:
>>> sum_of_multiples(n, 3) + sum_of_multiples(n, 5) - sum_of_multiples(n, 15)
233333334166666668
我正在完成 hackerrank 的项目欧拉问题 #1。 我写了一个蛮力解决方案来检查我的答案。它似乎是正确的,除了 10^9 的输入。 有人告诉我正确答案是:
233333333166666668
我回来了:
233333333166666680
n = 1000000000
sum_of_multiples_3 = int((int((n-1)/3.0)+1) * (int((n-1)/3.0)/2.0) * 3)
sum_of_multiples_5 = int((int((n-1)/5.0)+1) * (int((n-1)/5.0)/2.0) * 5)
sum_of_multiples_15 = int((int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15)
print(sum_of_multiples_3 + sum_of_multiples_5 - sum_of_multiples_15)
您正在使用整数除法的浮点除法:
int((n-1)/3.0)
更好地表示为
(n-1)//3
例如使用 Python 的 floor 除法运算符,不要使用浮点数,然后 floor.
使用整数底除法不会 运行 出现舍入问题,因为您将浮点运算扩展到超出其限制。
当您将 n
推得足够大时,您会看到此舍入错误:
>>> n = 100000000
>>> int((int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15)
333333316666665
>>> ((n-1)//15+1) * ((n-1)//15//2) * 15
333333316666665
>>> n = 1000000000
>>> int((int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15)
33333333166666664
>>> ((n-1)//15+1) * ((n-1)//15//2) * 15
33333333166666665
额外的 1 纯粹是因为您 运行 进入了浮点数的限制:
>>> (int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0)
2222222211111111.0
>>> ((n-1)//15+1) * ((n-1)//15//2)
2222222211111111
>>> (int((n-1)/15.0)+1) * (int((n-1)/15.0)/2.0) * 15
3.3333333166666664e+16
我不知道你为什么一直从 n
中减去一个;这根本不需要,并会导致不正确的结果。也许您正在尝试补偿浮点数舍入错误?正确的公式是:
(((n // 3) + 1) * (n // 3)) // 2 * 3
(((n // 5) + 1) * (n // 5)) // 2 * 5
(((n // 15) + 1) * (n // 15)) // 2 * 15
给我任何 n
:
>>> n = 1000000000
>>> sum_of_multiples_3 = (((n // 3) + 1) * (n // 3)) // 2 * 3
>>> sum_of_multiples_5 = (((n // 5) + 1) * (n // 5)) // 2 * 5
>>> sum_of_multiples_15 = (((n // 15) + 1) * (n // 15)) // 2 * 15
>>> sum_of_multiples_3 + sum_of_multiples_5 - sum_of_multiples_15
233333334166666668
我会在这里使用一个函数来计算倍数:
def sum_of_multiples(n, k):
k_in_n = n // k
return ((k_in_n + 1) * k_in_n) // 2 * k
因此您可以通过与暴力求和进行比较来验证它是否有效:
>>> sum(range(0, 10000 + 1, 3)) == sum_of_multiples(10000, 3)
True
>>> sum(range(0, 10000 + 1, 5)) == sum_of_multiples(10000, 5)
True
>>> sum(range(0, 10000 + 1, 15)) == sum_of_multiples(10000, 15)
True
然后用它来计算答案:
>>> sum_of_multiples(n, 3) + sum_of_multiples(n, 5) - sum_of_multiples(n, 15)
233333334166666668