【问题标题】:Stop Approximation in Complex Division in PythonPython中复杂除法的停止逼近
【发布时间】:2017-05-08 10:56:55
【问题描述】:

我一直在编写一些代码来列出 Python 中有理整数的高斯整数除数。 (与Project Euler问题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以下的有理整数没有出现这个问题?

提前感谢您的帮助。

【问题讨论】:

  • 这可能源于complex 在内部使用两个双精度数字来表示实部和虚部。您可以使用decimalround 来实现您自己的复数,并将结果精确到适当的小数位数。
  • 呃,if IsGaussian(n / complex(x, y)) == n: 应该做什么?它只能在 n = 0 或 n = 1 时为 True。您可能想摆脱 == n

标签: python division complex-numbers approximation


【解决方案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”。

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)

【讨论】:

  • 您可以将IsGaussian 的相关更改添加到您的答案中,以使其完整。 :-)
  • 按建议编辑。
  • 如果你使用cmath.isclose,你不需要四舍五入。这就是cmath.isclose 的实际意义。
  • 哦,是的,我现在看到您用舍入替换了转换为 int 的部分。我的错。
【解决方案2】:

您可以定义一个 epsilon,使用 round 舍入到所需的小数位数/精度(例如 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 的结果。您可能想要删除相等性检查。

【讨论】:

  • 看到@EfronLicht 的回答,用cmath.isclose 测试显然更好。
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 2018-04-25
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多