在 Python 中停止复数除法中的近似

Stop Approximation in Complex Division in Python

我一直在编写一些代码来列出 Python 中有理整数的高斯整数除数。 (与欧拉计划问题153相关)

我似乎在某些数字上遇到了一些麻烦,我相信这与 Python 近似复数除法有关。

这是我的函数代码:

def IsGaussian(z):
    #returns True if the complex number is a Gaussian integer
    return complex(int(z.real), int(z.imag)) == z

def Divisors(n):
    divisors = []

    #Firstly, append the rational integer divisors
    for x in range(1, int(n / 2 + 1)):
        if n % x == 0:
            divisors.append(x)

    #Secondly, two for loops are used to append the complex Guassian integer divisors
    for x in range(1, int(n / 2 + 1)):
        for y in range(1, int(n / 2 + 1)):
            if IsGaussian(n / complex(x, y)) == n:
                divisors.append(complex(x, y))
                divisors.append(complex(x, -y))

    divisors.append(n)

    return divisors

当我 运行 Divisors(29) 我得到 [1, 29],但是这漏掉了其他四个除数,其中一个是 (5 + 2j),可以清楚地看到分成29.

在 运行 宁 29 / complex(5, 2),Python 给出 (5 - 2.0000000000000004j)

这个结果不正确,应该是 (5 - 2j)。有什么办法可以绕过 Python 的近似值吗?为什么这个问题对于 100 以下的许多其他有理整数没有上升?

在此先感谢您的帮助。

您可以定义一个 epsilon,通过使用 round 舍入到所需的小数位数 places/precision(例如 10):

def IsGaussian(z, prec=10):
    # returns True if the complex number is a Gaussian integer
    # rounds the input number to the `prec` number of digits
    z = complex(round(z.real,prec), round(z.imag,prec))
    return complex(int(z.real), int(z.imag)) == z

不过您的代码还有另一个问题:

if IsGaussian(n / complex(x, y)) == n:

这只会给出 n = 0n = 1 的结果。您可能想删除相等性检查。

在内部,CPython 对复数使用一对双精度浮点数。一般来说,数值解的行为过于复杂,无法在此总结,但在数值计算中,一些错误是不可避免的。

EG:

>>>print(.3/3)
0.09999999999999999

因此,在测试此类解决方案时,使用近似相等而不是实际相等通常是正确的。

isclose function in the cmath module 正是出于这个原因。

>>>print(.3/3 == .1)
False
>>>print(isclose(.3/3, .1))
True

这类问题是Numerical Analysis的领域;对于有关此主题的进一步问题,这可能是一个有用的标签。

请注意,函数标识符被认为是 'pythonic' snake_case。

from cmath import isclose
def is_gaussian(z):
    #returns True if the complex number is a Gaussian integer
    rounded = complex(round(z.real), round(z.imag))
    return isclose(rounded, z)