计算每个数字的4次幂之和,为什么会得到错误的结果?

时间:2019-04-16 12:06:24

标签: python math

我正在尝试完成Project Euler question #30,因此决定根据已知答案验证我的代码。基本上问题是这样的:

  

找到所有可以写为数字的五次幂之和的数字之和。

这是我要用python证明的已知答案:

  

1634 = 1 ^ 4 + 6 ^ 4 + 3 ^ 4 + 4 ^ 4
  8208 = 8 ^ 4 + 2 ^ 4 + 0 ^ 4 + 8 ^ 4
  9474 = 9 ^ 4 + 4 ^ 4 + 7 ^ 4 + 4 ^ 4

     

由于1 = 1 ^ 4不是总和,所以不包括在内。

     

这些数字的总和是1634 + 8208 + 9474 = 19316。

运行代码时,我得到所有三个值加起来为19316,太好了! 但是在这些值中,有一个不正确的值:6688

这是我的代码:

i=1
answer = []

while True:
    list = []
    i=i+1
    digits = [int(x) for x in str(i)]

    for x in digits:
        a = x**4
        list.append(a)

        if sum(list) == i:
            print(sum(list))
            answer.append(sum(list))

list的总和将返回三个正确的值以及值6688。有人可以发现我错过的东西吗?

2 个答案:

答案 0 :(得分:7)

您正在过早检查总和。您检查数字中每个数字的匹配总和,并且6 ^ 4 + 6 ^ 4 + 8 ^ 46688。那是三位数,而不是全部四位数。

将您的sum()测试移出您的for循环:

for x in digits:
    a = x**4
    list.append(a)

if sum(list) == i:
    print(sum(list))
    answer.append(sum(list))

充其量最好已经超过目标时,您最好尽早丢弃数字:

digitsum = 0
for d in digits:
    digitsum += d ** 4
    if digitsum > i:
        break
else:
    if digitsum == i:
        answer.append(i)

但是我不会在这里烦恼,只是使用生成器表达式来组合确定数字,将它们提高到四次方,然后求和:

if sum(int(d) ** 4 for d in str(i)) == i:
    answer.append(i) 

您尚未定义上限,即数字始终大于其数字总和的点,您需要停止递增i。对于n次幂,您可以通过取9 ^ n,计算其位数,然后取9的n次幂中的位数> 的n次幂来找到这样的点。 9 。如果这样会创建更多位数的数字,请继续操作直到位数不再变化。

同样,您可以从i开始max(10, 1 + 2 ** n),因为您可以从数字中得出的最小总和将是单个2数字加上最小数字您可以舍弃的10位数字,并且在任何大于1的幂处,数字1和0以外的数字的幂始终大于数字值本身,并且您可以不要使用i = 1

def determine_bounds(n):
    """Given a power n > 1, return the lower and upper bounds in which to search"""
    nine_power, digit_count = 9 ** n, 1
    while True:
        upper = digit_count * nine_power
        new_count = len(str(upper))
        if new_count == digit_count:
            return max(10, 2 ** n), upper
        digit_count = new_count

如果将上述功能与传递给range(*<expression>)的{​​{1}}可变长度参数结合使用,则可以使用range()循环:

for

您可以在函数中确定一个数字是否等于其加到给定幂for i in range(*determine_bounds(4)): # ... 的数字的总和:

n

然后,您可以将所有内容放入列表推导中:

def is_digit_power_sum(i, n):
    return sum(int(d) ** n for d in str(i)) == i

>>> n = 4 >>> [i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n)] [1634, 8208, 9474] >>> n = 5 >>> [i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n)] [4150, 4151, 54748, 92727, 93084, 194979] 可以从大量的权力中受益;添加缓存会使4位数字输入的功能快两倍以上:

is_digit_power_sum()

当然,这个问题的解决方案是数字的总和:

def is_digit_power_sum(i, n, _cache={}):
    try:
        powers = _cache[n]
    except KeyError:
        powers = _cache[n] = {str(d): d ** n for d in range(10)}
    return sum(powers[d] for d in str(i)) == i

使用Python 3.8.0a3在我的2.9 GHz Intel Core i7 MacBook Pro上半秒内即可产生所需的输出。

答案 1 :(得分:1)

此处已修复:

i=1
answer = []

while True:
    list = []
    i=i+1
    digits = [int(x) for x in str(i)]

    for x in digits:
        a = x**4
       list.append(a)

       if sum(list) == i and len(list) == 4:
           print(sum(list))
           answer.append(sum(list))

我发现的错误:
6 ^ 4 + 6 ^ 4 + 8 ^ 4 = 6688
所以我只检查了清单的长度。