我在编写 Python 程序以解决数学问题时遇到的类型错误

A typeerror I face when writing a Python program in order to solve a maths problem

我一直在努力解决这个问题:

Find positive integer solutions for a,b,c that 1≤a<b<c≤30 and b/a+c/b+a/c is a positive integer.

所以我在 python 中写了这个:

for i,j,m in range(1,31):
    if i<=j and j<=m and j/i+m/j+i/m>=0:
        try:
            print(int(j/i+m/j+i/m))
        except TypeError:
            continue

但是没有用。

错误信息:

for i,j,m in range(1,31):
TypeError: cannot unpack non-iterable int object 

您想要分配 3 个变量,range() 仅 returns 一个值“列表”。

我不确定您要做什么,但我怀疑您想要尝试 ijm 的所有值组合。一种方法是创建嵌套循环。每个循环将迭代一个变量的值。

另一种解决方案是使用 itertools 并创建将由您的函数处理的所有组合的列表(这需要一些小的调整)。

遍历三元组

range returns 是单个整数的可迭代对象。要迭代三元组,您可以嵌套三个循环,或使用 itertools:

# using nested loops
for a in range(1, 29):
    for b in range(a+1, 30):
        for c in range(b+1, 31):
            ...

# using itertools
from itertools import combinations

for a,b,c in combinations(range(1,31), 3):
   ...

请注意,在这两种情况下,我都编写了循环以直接遍历满足 a < b < c 的三元组 (a,b,c)。这比迭代所有三元组 (a,b,c),然后过滤条件 a < b < c.

更有效

测试b/a+c/b+a/c是否是一个整数

在处理不同分母的分数时,首先要做的通常是把所有的东西都归为一个公分母。在这种情况下,三个分数 b/a+c/b+a/c 的总和等于分数 (b*b*c + c*a*c + a*a*b) / (a*b*c)。测试这个分数是否为整数,就是测试它的分子是否可以被它的分母整除。这可以通过模运算符 %.

轻松实现
if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0:
    ...

这实际上比使用 floating-point 除法和测试结果是否像整数要好。 Floating-point 除法结果为二进制 floating-point 数。并不是所有的数字都可以用二进制 floating-point 精确表示:就像分数 1/3 不能用十进制精确表示一样,很多数字也不能用二进制精确表示。想象一下测试 1/3 + 1/3 + 1/3 是否为整数:如果 1/3 舍入为 0.333,那么我们将得到 0.333 + 0.333 + 0.333 == 0.999,这不是整数。这是一个近似误差。如果可能,在处理整数运算时,始终只使用整数,而不要使用 floating-point 除法。保护自己免受 floating-point 近似值的影响!

从input/output

中分离算法逻辑

将处理算法和算术的代码部分与处理打印到屏幕、读取和写入文件等的代码部分分开是一个很好的做法。

您可以将找到的所有三元组附加到列表中,然后 return 列表:

def get_triplet_list(n):
    l = []
    for a,b,c in combinations(range(1, n+1), 3):
        if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0:
            l.append((a,b,c))
    return l

def main():
    l = get_triplet_list(30)
    for a,b,c in l:
        print(a,b,c)

if __name__ == '__main__':
    main()
# 2 9 12
# 3 4 18
# 4 18 24

或者使用列表理解:

def get_triplet_list(n):
    return [(a,b,c) for a,b,c in combinations(range(1, n+1), 3) if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0]

def main():
    l = get_triplet_list(30)
    for a,b,c in l:
        print(a,b,c)

if __name__ == '__main__':
    main()

或者使用生成器函数,使用关键字 yield 而不是 return:

def gen_triplets(n):
    for a,b,c in combinations(range(1, n+1), 3):
        if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0:
            yield (a,b,c)

def main():
    for a,b,c in gen_triplets(30):
        print(a,b,c)

if __name__ == '__main__':
    main()