Реализация сравнения комплексных чисел в 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
это, кажется, работает, но у меня есть несколько вопросов:
- это путь или есть лучшая альтернатива?
- Я хотел бы, чтобы мой пакет прозрачно работал со встроенным
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