2012-11-14 12 views
17

Zastanawiam się, w jaki sposób Python (3.3.0) drukuje liczby zespolone. Szukam wyjaśnienia, a nie sposobu na zmianę druku.Format liczby zespolonej w Pythonie

Przykład:

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

Dlaczego nie po prostu wydrukować "0"? Domyślam się: zachować wydajność złożonego typu.

Następny przykład:

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

Cóż, to proste "-1j" lub "(-1j)" zrobiłby. I dlaczego "-0" ?? Czy to nie to samo co +0? To nie wydaje się być problemem zaokrąglania:

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

A gdy część urojona dostaje pozytywne, -0 znika:

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

kolejny przykład:

>>> 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 

Am Brak tu czegoś?

+0

chodzi o '0j' części, to powszechna praktyka w Pythonie, że' eval (repr (x)) == x' –

Odpowiedz

14

Drukuje 0j, aby wskazać, że nadal jest to wartość complex. Można także wpisać go w ten sposób:

>>> 0j 
0j 

Reszta jest prawdopodobnie wynikiem magii IEEE 754 floating point representation, co czyni rozróżnienie między 0 i -0, tzw signed zero. Zasadniczo istnieje jeden bit, który mówi, czy liczba jest dodatnia czy ujemna, niezależnie od tego, czy liczba ta wynosi zero. To wyjaśnia, dlaczego 1j * -1 daje coś z ujemną częścią rzeczywistą: dodatnie zero zostało pomnożone przez -1.

-0 jest wymagane przez standard do porównania równego +0, co wyjaśnia, dlaczego (1j * -1).real == 0.0 nadal jest przechowywane.

Powodem, że Python nadal decyduje się na wydrukowanie -0, jest to, że w złożonym świecie to mieć znaczenie dla cięć gałęzi, na przykład w the phase function:

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

Chodzi o części urojonej, nie Prawdziwa część, ale łatwo jest wyobrazić sobie sytuacje, w których znak prawdziwej części spowodowałby podobną różnicę.

+2

Chcę tylko dodać do tej odpowiedzi, że wszystkie opisane przypadki są ważne i Python prace zgodnie z oczekiwaniami. Możesz znaleźć specjalny przypadek testowy ze wszystkimi reprezentacjami w stosunku do IEEE 754: 'Lib/tests/test_complex.py',' test_negative_zero_repr_str' –

+1

Po prostu przetestowano i wygląda na to, że masz rację co do '-0':' >>> 0j.real .hex() ' ' '0x0.0p + 0'' '>>> (0j * -1) .real.hex()' '' -0x0,0p + 0'' –

+0

Potwierdzam' - 0' part: 'print (0.0 * -1)' drukuje "' -0.0 ". A ponieważ "złożony" typ w Pythonie to para liczb _float_, nie ma znaczenia, czy podałeś część ułamkową, czy nie. –

1

Jeśli chodzi o pierwsze pytanie dotyczy: czy to tylko drukowane 0 byłoby matematycznie poprawne, ale nie wiesz, że mieli do czynienia z obiektem vs complex z int. Dopóki nie określisz wartości .real, zawsze otrzymasz komponent J.

Nie jestem pewien, dlaczego kiedykolwiek dostaniesz -0; nie jest to technicznie niepoprawne (-1 * 0 = 0), ale jest dziwne pod względem syntaktycznym.

Jeśli chodzi o resztę, to dziwne, że nie jest spójna, jednak żadna nie jest poprawna technicznie, tylko artefakt wdrożenia.

3

Odpowiedź dotyczy samego kodu źródłowego Python.

Będę pracować z jednym z twoich przykładów. Niech

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

Kiedy robisz a*b dzwonisz this function:

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

A jeśli nie, że interpreter Pythona, dostaniesz

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

Od IEEE 754, ty otrzymujesz numer negative zero, a od that's not +0 dostajesz pareny i część rzeczywistą podczas drukowania.

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. */ 
... 

Chyba (ale nie wiem na pewno), że uzasadnienie pochodzi od znaczenia tego znaku przy obliczaniu z elementarnych złożonych funkcji (jest odniesienie do tego w artykule wikipedia na podpisanym zero).

2
  • 0j jest imaginary literal która rzeczywiście wskazuje liczbę zespoloną zamiast całkowitą lub zmiennoprzecinkowych jeden.

  • +-0 ("podpisane zero") jest wynikiem zgodności Pythona z IEEE 754 floating point representation, ponieważ w języku Python, complex is by definition a pair of floating point numbers. Z tego powodu nie ma potrzeby drukowania ani określania części o ułamkach zero dla modelu complex.

  • -0 część jest drukowane aby dokładnie reprezentują zawartość as repr()'s documentation demands (repr() niejawnie wywoływana zawsze wynik danego przedsięwzięcia jest przekazywany do konsoli).

  • Jeśli chodzi o pytanie dlaczego (-0+1j) = 1j, ale (1j*-1) = (-0+1j). Zauważ, że (-0+0j) lub (-0.0+0j) nie są pojedynczymi liczbami zespolonymi ale wyrażenia - AN int/float dodane do complex. Aby obliczyć wynik, najpierw należy przekonwertować pierwszą liczbę na complex (-0 ->(0.0,0.0), ponieważ liczby całkowite nie mają zer podpisu, -0.0 ->(-0.0,0.0)). Następnie jego .real i dodano do odpowiednich 1j, które są (+0.0,1.0). Wynikiem jest (+0.0,1.0): ^). Aby zbudować kompleks bezpośrednio, użyj complex(-0.0,1).

+0

Dzięki za wyjaśnienie dotyczące str/repr. Ale tutaj "print (0j * -1)" nadal zwraca "(-0 + 0j)", więc zachowuje się tak samo. Co więcej, * jeśli * python tak ściśle przylega do standardu IEEE z jego repr(), dlaczego "print (-0 + 0j)" zwraca "0j"? – cxxl

+0

2cxxl: '(-0 + 0j)' nie jest pojedynczą liczbą zespoloną, ale wyrażeniem - liczbą całkowitą dodaną do kompleksu. Kiedy wynik jest obliczany, '-0' jest konwertowane do kompleksu i dodawane do jego' .real', które jest '0'. Wynikiem jest '+ 0': ^) –

+0

Ponieważ moje założenie dotyczące' str() 'okazało się w tym przypadku fałszywe, wyczyściłem je. –

Powiązane problemy