我最近正在研究一些项目Euler问题
2520是最小的数字,可以除以1到10的每个数字而没有余数。
能被1到20的所有数均分的最小正数是多少?
我编写了代码,效果很好
def factor_finder(n, j=2):
factor_list = []
if n == 2:
return [2]
elif n == 3:
return [3]
else:
while n >= j * 2:
while n % j == 0:
n = int(n / j)
factor_list.append(j)
j += 1
if n > 1:
factor_list.append(n)
return factor_list
def smallest_multiples(n):
from functools import reduce
factor_list = []
final_list = []
for i in range(2, n + 1):
factor_list += factor_finder(i)
# print(factor_list)
for i in set(factor_list):
l1 = []
l2 = []
for j in factor_list:
if j == i:
l1.append(j)
else:
if len(l1) > len(l2):
l2 = l1
l1 = []
else:
l1 = []
# print(l2)
final_list += l2
# print(final_list)
return (
np.array(final_list).cumprod()[-1],
reduce((lambda x, y: x * y), final_list),
)
结果是:
%time
smallest_multiples(1000)
CPU时间:用户5 µs,sys:0 ns,总计:5 µs 墙时间:32.4 µs
(-4008056434385126912, 7128865274665093053166384155714272920668358861885893040452001991154324087581111499476444151913871586911717817019575256512980264067621009251465871004305131072686268143200196609974862745937188343705015434452523739745298963145674982128236956232823794011068809262317708861979540791247754558049326475737829923352751796735248042463638051137034331214781746850878453485678021888075373249921995672056932029099390891687487672697950931603520000)
我的问题是为什么numpy.cumprod()无法获得正确的数字。我认为numpy是非常多的工具。有人可以给我一些想法吗?
答案 0 :(得分:1)
数值分析不是数论。正确性不是唯一的目标,但必须权衡效率。任意精度数字(如大整数)都很慢,因此numpy默认使用固定长度的整数。当它们变得太大时,它们只会溢出。您可以指示numpy使用任意精度的整数,但是会损失很多速度:
np.arange(1, 100).prod() # fast but wrong
# 0
np.arange(1, 100, dtype=object).prod() # slow but correct
# 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000
答案 1 :(得分:1)
问题是数字达到了一个大小,这意味着它不再可以由Python中的int表示。如果您查看here,则会看到int的最大长度约为19位数字(即63位+符号位的2 ^ 63),然后进入溢出状态。 Numpy基于C,它使用固定精度进行更快的计算,但要取舍的是它受64位整数限制并且会溢出。 numpy中的某些函数甚至可以通过转换为浮点数来进行计算(甚至可以容纳更多数字)来防止这种情况发生。
如果您告诉numpy使用“对象”作为数据类型,则将耗费大量时间,但它会让您使用Python中惯用的任意精度。对于您的代码,它看起来像:
return (
np.cumprod(final_list, dtype="object")[-1],
reduce((lambda x, y: x * y), final_list),
)