-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathOOP2.py
More file actions
executable file
·191 lines (153 loc) · 5.52 KB
/
OOP2.py
File metadata and controls
executable file
·191 lines (153 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env python3
"""
Dies ist ein Beispiel für Vererbung.
Wir implementieren hier die komplexen Zahlen,
indem wir von der abstrakten Klasse numbers.Complex erben
und die relevanten Methoden schreiben.
(Wenn man einfach nur mit komplexen Zahlen rechnen möchte,
ist dieser Aufwand nicht nötig oder sinnvoll.
`complex` ist bereits in der Standardbibliothek enthalten.)
Siehe auch https://docs.python.org/3.7/library/numbers.html.
Abstrakte Klassen kann man auch selber definieren, siehe dazu:
https://docs.python.org/3/library/abc.html
Bei den Rückgabetypen ist `C` in Anführungszeichen gefasst,
weil der Typ zu den Zeitpunkt noch nicht definiert ist.
(Ab Python 3.7 wäre das nicht mehr nötig, siehe dazu PEP 563.)
"""
from numbers import Complex
from math import sqrt
__all__ = ["C"]
class C(Complex):
"""
Komplexe Zahlen haben einen Real- und einen Imaginärteil.
Sie werden häufig als a + bi geschrieben,
wobei a der Realteil und b der Imaginärteil ist.
Man kann sie sich auch als zweidimensionalen Vektorraum vorstellen, der 1 + 0i (bzw. (1, 0)) und 0 + 1i (bzw. (0, 1)) als Basisvektoren hat, d.h. eine Dimension ist der Realteil und die andere Dimension ist der Imaginärteil
"""
real = 0 # type: float
imag = 0 # type: float
def __init__(self, real: float = 0, imag: float = 0) -> None:
"""
Erstellt eine neue komplexe Zahl.
Sowohl Real- als auch Imaginärteil können weggelassen werden,
dann wird einfach 0 angenommen.
"""
self.real = real
self.imag = imag
def __abs__(self) -> float:
"""
Berechnet den Betrag einer komplexen Zahl.abs
Mit der Vektordarstellung (real, imag) sollte das klar sein
- das ist nur der Satz von Pythagoras.
"""
return sqrt(self.real**2 + self.imag**2)
def __add__(self, o: Complex) -> "C":
"""
Addiert zwei komplexe Zahlen.
Mit der Vektordarstellung sollte das klar sein:
g = (a, b), h = (c, d), g + h = (a + c, b + d)
"""
assert isinstance(o, Complex)
return C(self.real + o.real, self.imag + o.imag)
def __radd__(self, o: float) -> "C":
"""
Addiert eine rationale Zahl zu einer komplexen Zahl.
Hierbei ändert sich einfach nur der Realteil.
"""
assert isinstance(o, float)
return C(self.real + o, self.imag)
def __mul__(self, o: Complex) -> "C":
"""
Multipliziert zwei komplexe Zahlen.
"""
assert isinstance(o, Complex)
return C(
real=self.real * o.real - self.imag * o.imag,
imag=self.real * o.imag + self.imag * o.real
)
def __rmul__(self, o: float) -> "C":
"""
Multipliziert eine rationale Zahl an eine komplexe Zahl.
Hierbei ändert sich nur der Realteil.
"""
assert isinstance(o, float)
return C(self.real * o, self.imag)
def __pow__(self, o: int) -> "C":
"""
Potenziert eine komplexe Zahl.
"""
assert o >= 0
value = C(1, 1)
for i in range(o):
value *= self
return value
def __rpow__(self, o: float) -> "C":
"""
Potenziert nur den Realteil.
"""
return C(self.real ** o, self.imag)
def __truediv__(self, o: Complex) -> "C":
"""
Dividiert zwei komplexe Zahlen.
"""
assert isinstance(o, Complex)
return C(
real=(self.real * o.real + self.imag * o.imag) / (o.real ** 2 + o.imag ** 2),
imag=(self.imag * o.real - self.real * o.imag) / (o.real ** 2 + o.imag ** 2)
)
def __rtruediv__(self, o: float) -> "C":
"""
Dividiert eine komplexe Zahl durch eine rationale Zahl.
Hierbei ändert sich nur der Realteil.
"""
return C(self.real / o, self.imag)
def __eq__(self, o: object) -> bool:
"""
Vergleicht zwei komplexe Zahlen auf Äquivalenz.
Mit der Vektordarstellung sollte das klar sein:
g = (a, b), h = (c, d), (g = h) <=> (a = c ^ b = c)
"""
if not isinstance(o, Complex):
return False
return (self.real == o.real) and (self.imag == o.imag)
def conjugate(self) -> "C":
"""
Berechnet das komplexe Konjugat einer komplexen Zahl.
"""
return C(self.real, -self.imag)
def __pos__(self) -> "C":
"""
Berechnet +x (für x eine komplexe Zahl).
"""
return self
def __neg__(self) -> "C":
"""
Berechnet -x (für x eine komplexe Zahl).
"""
return C(-self.real, -self.imag)
def __complex__(self) -> complex:
"""
Wandelt eine komplexe Zahl in eine complex-Instanz um.
"""
return complex(self.real, self.imag)
def __hash__(self) -> int:
"""
Berechnet den Hashwert einer komplexen Zahl.
Wichtig ist: Wenn zwei Zahlen äquivalent sind, sollen sie den gleichen Hash haben.
Wir machen es uns einfach und nehmen einfach die menschen-lesbare Darstellung.
"""
return hash(repr(self))
def __repr__(self) -> str:
"""
Stellt eine komplexe Zahl menschen-lesbar dar.
Dies gibt die Darstellung a + b i,
nicht die Vektordarstellung (a, b) zurück.
"""
if self.imag >= 0:
fstr = "{} + {}i"
else:
fstr = "{} - {}i"
return fstr.format(self.real, self.imag)
if __name__ == "__main__":
# Hier könnte Code stehen.
pass