|
|
@@ -0,0 +1,158 @@
|
|
|
+import math
|
|
|
+
|
|
|
+class complex:
|
|
|
+ def __init__(self, real, imag=0):
|
|
|
+ self._real = float(real)
|
|
|
+ self._imag = float(imag)
|
|
|
+
|
|
|
+ @property
|
|
|
+ def real(self):
|
|
|
+ return self._real
|
|
|
+
|
|
|
+ @property
|
|
|
+ def imag(self):
|
|
|
+ return self._imag
|
|
|
+
|
|
|
+ def __repr__(self):
|
|
|
+ return f"({self.real}+{self.imag}j)"
|
|
|
+
|
|
|
+ def __eq__(self, other):
|
|
|
+ if type(other) is complex:
|
|
|
+ return self.real == other.real and self.imag == other.imag
|
|
|
+ if type(other) in (int, float):
|
|
|
+ return self.real == other and self.imag == 0
|
|
|
+ return NotImplemented
|
|
|
+
|
|
|
+ def __add__(self, other):
|
|
|
+ if type(other) is complex:
|
|
|
+ return complex(self.real + other.real, self.imag + other.imag)
|
|
|
+ if type(other) in (int, float):
|
|
|
+ return complex(self.real + other, self.imag)
|
|
|
+ return NotImplemented
|
|
|
+
|
|
|
+ def __radd__(self, other):
|
|
|
+ return self.__add__(other)
|
|
|
+
|
|
|
+ def __sub__(self, other):
|
|
|
+ if type(other) is complex:
|
|
|
+ return complex(self.real - other.real, self.imag - other.imag)
|
|
|
+ if type(other) in (int, float):
|
|
|
+ return complex(self.real - other, self.imag)
|
|
|
+ return NotImplemented
|
|
|
+
|
|
|
+ def __rsub__(self, other):
|
|
|
+ if type(other) is complex:
|
|
|
+ return complex(other.real - self.real, other.imag - self.imag)
|
|
|
+ if type(other) in (int, float):
|
|
|
+ return complex(other - self.real, -self.imag)
|
|
|
+ return NotImplemented
|
|
|
+
|
|
|
+ def __mul__(self, other):
|
|
|
+ if type(other) is complex:
|
|
|
+ return complex(self.real * other.real - self.imag * other.imag,
|
|
|
+ self.real * other.imag + self.imag * other.real)
|
|
|
+ if type(other) in (int, float):
|
|
|
+ return complex(self.real * other, self.imag * other)
|
|
|
+ return NotImplemented
|
|
|
+
|
|
|
+ def __rmul__(self, other):
|
|
|
+ return self.__mul__(other)
|
|
|
+
|
|
|
+ def __pow__(self, other: int | float):
|
|
|
+ if type(other) in (int, float):
|
|
|
+ return complex(self.__abs__() ** other * math.cos(other * phase(self)),
|
|
|
+ self.__abs__() ** other * math.sin(other * phase(self)))
|
|
|
+ return NotImplemented
|
|
|
+
|
|
|
+ def __abs__(self) -> float:
|
|
|
+ return math.sqrt(self.real ** 2 + self.imag ** 2)
|
|
|
+
|
|
|
+
|
|
|
+# Conversions to and from polar coordinates
|
|
|
+
|
|
|
+def phase(z: complex):
|
|
|
+ return math.atan2(z.imag, z.real)
|
|
|
+
|
|
|
+def polar(z: complex):
|
|
|
+ return z.__abs__(), phase(z)
|
|
|
+
|
|
|
+def rect(r: float, phi: float):
|
|
|
+ return r * math.cos(phi) + r * math.sin(phi) * 1j
|
|
|
+
|
|
|
+# Power and logarithmic functions
|
|
|
+
|
|
|
+def exp(z: complex):
|
|
|
+ return math.exp(z.real) * rect(1, z.imag)
|
|
|
+
|
|
|
+def log(z: complex, base=2.718281828459045):
|
|
|
+ return math.log(z.__abs__(), base) + phase(z) * 1j
|
|
|
+
|
|
|
+def log10(z: complex):
|
|
|
+ return log(z, 10)
|
|
|
+
|
|
|
+def sqrt(z: complex):
|
|
|
+ return z ** 0.5
|
|
|
+
|
|
|
+# Trigonometric functions
|
|
|
+
|
|
|
+def acos(z: complex):
|
|
|
+ return -1j * log(z + sqrt(z * z - 1))
|
|
|
+
|
|
|
+def asin(z: complex):
|
|
|
+ return -1j * log(1j * z + sqrt(1 - z * z))
|
|
|
+
|
|
|
+def atan(z: complex):
|
|
|
+ return 1j / 2 * log((1 - 1j * z) / (1 + 1j * z))
|
|
|
+
|
|
|
+def cos(z: complex):
|
|
|
+ return (exp(z) + exp(-z)) / 2
|
|
|
+
|
|
|
+def sin(z: complex):
|
|
|
+ return (exp(z) - exp(-z)) / (2 * 1j)
|
|
|
+
|
|
|
+def tan(z: complex):
|
|
|
+ return sin(z) / cos(z)
|
|
|
+
|
|
|
+# Hyperbolic functions
|
|
|
+
|
|
|
+def acosh(z: complex):
|
|
|
+ return log(z + sqrt(z * z - 1))
|
|
|
+
|
|
|
+def asinh(z: complex):
|
|
|
+ return log(z + sqrt(z * z + 1))
|
|
|
+
|
|
|
+def atanh(z: complex):
|
|
|
+ return 1 / 2 * log((1 + z) / (1 - z))
|
|
|
+
|
|
|
+def cosh(z: complex):
|
|
|
+ return (exp(z) + exp(-z)) / 2
|
|
|
+
|
|
|
+def sinh(z: complex):
|
|
|
+ return (exp(z) - exp(-z)) / 2
|
|
|
+
|
|
|
+def tanh(z: complex):
|
|
|
+ return sinh(z) / cosh(z)
|
|
|
+
|
|
|
+# Classification functions
|
|
|
+
|
|
|
+def isfinite(z: complex):
|
|
|
+ return math.isfinite(z.real) and math.isfinite(z.imag)
|
|
|
+
|
|
|
+def isinf(z: complex):
|
|
|
+ return math.isinf(z.real) or math.isinf(z.imag)
|
|
|
+
|
|
|
+def isnan(z: complex):
|
|
|
+ return math.isnan(z.real) or math.isnan(z.imag)
|
|
|
+
|
|
|
+def isclose(*args, **kwargs):
|
|
|
+ raise NotImplementedError
|
|
|
+
|
|
|
+# Constants
|
|
|
+
|
|
|
+pi = math.pi
|
|
|
+e = math.e
|
|
|
+tau = 2 * pi
|
|
|
+inf = math.inf
|
|
|
+infj = complex(0, inf)
|
|
|
+nan = math.nan
|
|
|
+nanj = complex(0, nan)
|