Реализация сравнения комплексных чисел в Python?

Я знаю, что операторы сравнения с комплексными числами не могут быть определены в целом. Вот почему Python бросает!--1--> исключение при попытке использовать готовое комплексное сравнение. Я понимаю, почему это так (пожалуйста, не уходите от темы, пытаясь объяснить, почему два комплексных числа не могут быть сравнены).

тем не менее, в этом конкретном случае я хотел бы реализовать комплексное сравнение чисел на основе их величин. Другими словами, для z1 и z2 комплексные значения, тогда z1 > z2 если-и-только-если abs(z1) > abs(z2), где abs() реализует значение комплексного числа, как в numpy.abs().

я придумал решение (по крайней мере, я думаю, что у меня) следующим образом:

import numpy as np

class CustomComplex(complex):
    def __lt__(self, other):
        return np.abs(self) < np.abs(other)
    def __le__(self, other):
        return np.abs(self) <= np.abs(other)
    def __eq__(self, other):
        return np.abs(self) == np.abs(other)
    def __ne__(self, other):
        return np.abs(self) != np.abs(other)
    def __gt__(self, other):
        return np.abs(self) > np.abs(other)
    def __ge__(self, other):
        return np.abs(self) >= np.abs(other)

complex = CustomComplex

это, кажется, работает, но у меня есть несколько вопросов:

  1. это путь или есть лучшая альтернатива?
  2. Я хотел бы, чтобы мой пакет прозрачно работал со встроенным complex тип данных, а также numpy.complex. Как можно ли это сделать элегантно, без дублирования кода?

2 ответов


боюсь, я буду не в теме (да, я полностью прочитал ваш пост : -)). Хорошо, Python позволяет вам сравнивать комплексные числа таким образом, потому что вы можете определить отдельно все операторы, даже если я настоятельно рекомендую вам не переопределить __eq__ Как ты сделал: ты are слова 1 == -1 !

IMHO проблема лежит там и будет прыгать на вашем лице в один момент (или на лице любого, кто будет использовать ваш пакет) : при использовании равенства и неравенства, обычные смертные (и большинство кода python) делают простые предположения, такие как -1 != 1 и (a <= b) && (b <= a) подразумевает a == b. И вы просто не можете иметь эти 2 предположения верными одновременно по чисто математическим причинам.

еще одно классическое предположение -a <= b эквивалентно -b <= -a. Но с вами предзаказ a <= b эквивалентно -a <= -b !

при этом, я постараюсь ответить на ваши 2 вопроса :

  • 1: ИМХО это вредный способ (как указано выше), но у меня нет лучшей альтернативы ...
  • 2: я думаю, что mixin может быть элегантным способом ограничения дублирования кода

пример кода (на основе вашего собственного кода, но не широко протестирован):

import numpy as np

class ComplexOrder(Object):
    def __lt__(self, other):
        return np.absolute(self) < np.absolute(other)
    # ... keep want you want (including or not eq and ne)
    def __ge__(self, other):
        return np.absolute(self) >= np.absolute(other)

class OrderedComplex(ComplexOrder, complex):
    def __init__(self, real, imag = 0):
        complex.__init__(self, real, imag)

class NPOrderedComplex64(ComplexOrder, np.complex64):
    def __init__(self, real = 0):
        np.complex64.__init__(self, real)

я откажусь от всех причин, почему это может быть плохой идеей, согласно вашей просьбе.

это путь или есть лучшая альтернатива?

нет необходимости идти с numpy, когда нормальный abs принимает комплексные числа и гораздо быстрее*. Есть также удобный total_ordering на functools это хорошо работает для таких простых сравнений, если вы хотите уменьшить код (но это может быть медленнее):

from functools import total_ordering
@total_ordering
class CustomComplex(complex):
    def __eq__(self, other):
        return abs(self) == abs(other)
    def __lt__(self, other):
        return abs(self) < abs(other)

(это весь код, который вы необходимость.)


Я хотел бы, чтобы мой пакет прозрачно работал со встроенным сложным типом данных, а также numpy.сложный. Как это можно сделать элегантно, без дублирования кода?

он автоматически работает, когда правильный аргумент является нормальным сложным (или любым) числом:

>>> CustomComplex(1+7j) < 2+8j
True

но это лучшее, что вы можете сделать, если вы хотите использовать операторы < etc. и не функции. The complex type не позволяет установить __lt__ и TypeError жестко закодирован.

если вы хотите сделать такие сравнения на normal complex numbers, вы должны определить и использовать свои собственные функции сравнения вместо обычных операторов. Или просто используйте abs(a) < abs(b) что ясно и не очень многословно.


* сроки-в abs и numpy.abs:

>>> timeit.timeit('abs(7+6j)')
0.10257387161254883
>>> timeit.timeit('np.abs(7+6j)', 'import numpy as np')
1.6638610363006592