Формат комплексного номера в Python - программирование

Формат комплексного номера в Python

Мне интересно, как Python (3.3.0) печатает сложные числа. Я ищу объяснение, а не способ изменить печать.

Пример:

>>> complex(1,1)-complex(1,1)
0j

Почему он просто не печатает "0"? Мое предположение: сохранить вывод сложного типа.

Следующий пример:

>>> complex(0,1)*-1
(-0-1j)

Ну, простой "-1j" или "(-1j)" сделал бы. И почему "-0"?? Разве это не так, как +0? Это не похоже на проблему округления:

>>> (complex(0,1)*-1).real == 0.0
True

И когда мнимая часть становится положительной, -0 исчезает:

>>> complex(0,1)
1j
>>> complex(0,1)*-1
(-0-1j)
>>> complex(0,1)*-1*-1
1j

Еще один пример:

>>> complex(0,1)*complex(0,1)*-1
(1-0j)
>>> complex(0,1)*complex(0,1)*-1*-1
(-1+0j)
>>> (complex(0,1)*complex(0,1)*-1).imag
-0.0

Я что-то пропустил?

4b9b3361

Ответ 1

Он печатает 0j, чтобы указать, что он все еще имеет значение complex. Вы также можете ввести его так:

>>> 0j
0j

Остальное, вероятно, является результатом магии представления IEEE 754 с плавающей запятой, что делает различие между 0 и -0, так называемым подписанный нуль. В принципе, есть один бит, который говорит, является ли число положительным или отрицательным, независимо от того, является ли число нулевым. Это объясняет, почему 1j * -1 дает что-то с отрицательной нулевой вещественной частью: положительный нуль умножается на -1.

-0 требуется стандартом для сравнения равным +0, что объясняет, почему (1j * -1).real == 0.0 все еще сохраняется.

Причина, по которой Python по-прежнему решает распечатать -0, заключается в том, что в сложном мире они имеют значение для разрезов ветвей, например, в phase function:

>>> phase(complex(-1.0, 0.0))
3.141592653589793
>>> phase(complex(-1.0, -0.0))
-3.141592653589793

Речь идет о мнимой части, а не о реальной части, но легко представить ситуации, в которых знак реальной части будет иметь аналогичную разницу.

Ответ 2

Ответ лежит на исходном коде Python.

Я буду работать с одним из ваших примеров. Пусть

a = complex(0,1)
b = complex(-1, 0)

Когда вы делаете a*b, вы вызываете эту функцию:

real_part = a.real*b.real - a.imag*b.imag
imag_part = a.real*b.imag + a.imag*b.real

И если вы сделаете это в интерпретаторе python, вы получите

>>> real_part
-0.0
>>> imag_part
-1.0

Из IEEE754 вы получаете отрицательный нуль, а так как что не +0, вы получаете парсеры и реальную часть при ее печати. ​​

if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) {
    /* Real part is +0: just output the imaginary part and do not
       include parens. */
...
else {
    /* Format imaginary part with sign, real part without. Include
       parens in the result. */
...

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

Ответ 3

  • 0j представляет собой мнимый литерал, который действительно указывает на комплексное число, а не целое число или число с плавающей запятой.

  • +-0 ( "signed zero" ) является результатом соответствия Python IEEE 754 с плавающей запятой, поскольку в Python, complex по определению представляет пару чисел с плавающей запятой. Из-за последнего нет необходимости печатать или указывать части с нулевой долей для complex тоже.

  • Часть -0 печатается для точного представления содержимого как repr() требует документации (repr() is неявно вызываемый всякий раз, когда результат операции выводится на консоль).

  • Относительно вопроса почему (-0+1j) = 1j, но (1j*-1) = (-0+1j). Обратите внимание, что (-0+0j) или (-0.0+0j) не являются единичными комплексными числами, а выражения - a int/float, добавленные к complex. Чтобы вычислить результат, сначала первое число преобразуется в complex (-0(0.0,0.0), поскольку целые числа не имеют подписанных нулей, -0.0(-0.0,0.0)). Затем его .real и .imag добавляются к соответствующим 1j, которые являются (+0.0,1.0). Результат (+0.0,1.0): ^). Чтобы построить комплекс напрямую, используйте complex(-0.0,1).

Ответ 4

Что касается первого вопроса: если он просто напечатал 0, он был бы математически корректным, но вы не знали бы, что имеете дело с объектом complex vs a int. Пока вы не укажете .real, вы всегда получите J-компонент.

Я не уверен, почему вы когда-нибудь получите -0; это не технически неверно (-1 * 0 = 0), но оно синтаксически нечетно.

Что касается остального, странно, что он несовместим, однако ни один из них не является технически правильным, а просто артефактом реализации.