This module implements cplx class (complex numbers) regardless to the built-in class. The main goal of this module is to propose some improvement to complex numbers in python and deal with them from a mathematical approach. Also cplx class doesn't support the built-in class intentionally, as the idea was to give an alternative to it. With the hope I managed to succeed, here is the module : -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20170904/f47fafbc/attachment.html> -------------- next part -------------- # Module for complex numbers (doesn't support the built-in complex class) # Originally contributed by TBER Abdelmalek import re, math from fractions import Fraction as Q if __name__ == '__main__' : import os, Complex help(Complex) os.system("pause") _supported = (int, float, Q, str, tuple, list) # Supported types for instanciation and operations for cplx class class cplx : """This class implements complex numbers at the form of 'a+bi' with a : the real part, and b : the imaginary part. a and b are real numbers : [integers, floating numbers, or fractions (from Fraction class of fractions module), refered here by Q]. Construction of complex numbers can be from two major ways : - cplx([real part[, imaginary part]]) : Two real numbers arguments given and both optionals, so that cplx() = 0 For fractions use Fraction class : cplx(Q(n,d),Q(n',d')) for details about Fraction, see help(Fraction). -cplx('valid form of a complex number in a STRING'): The advantage of this way is the ease of fractions use with '/'. Examples : cplx('2i-1/4') cplx('6 - 1/5 * i') # spaces don't bother at all cplx('7i') """ global _supported def __init__(self, a=0, b=None): if isinstance(a, str) and b is None: # construction from string if a == '' : self.re = 0 self.im = 0 elif cplx.verify(a): part_one = '' part_two = '' switch = False first = True for c in a : if c in ('+', '-') and not first : switch = True part_two += c elif not switch : if c.isalnum() or c in ('+', '-', '/') : part_one += c elif c in (',', '.') : part_one += '.' else : if c.isalnum() or c == '/' : part_two += c elif c in (',', '.') : part_two += '.' first = False if 'i' in part_two : part_two = part_two[:len(part_two)-1] if '.' in part_one : self.re = float(part_one) elif '/' in part_one : self.re = Q(part_one) else : self.re = int(part_one) if '.' in part_two : self.im = float(part_two) elif '/' in part_two : self.im = Q(part_two) elif part_two == '+' : self.im = 1 elif part_two == '-' : self.im = -1 else : self.im = int(part_two) elif 'i' in part_one : part_one = part_one[:len(part_one)-1] if part_two == '' : self.re = 0 elif '.' in part_two : self.re = float(part_two) elif '/' in part_two : self.re = Q(part_two) else : self.re = int(part_two) if '.' in part_one : self.im = float(part_one) elif '/' in part_one : self.im = Q(part_one) elif part_one == '' or part_one == '+' : self.im = 1 elif part_one == '-' : self.im = -1 else : self.im = int(part_one) else : if '.' in part_one : self.re = float(part_one) elif '/' in part_one : self.re = Q(part_one) else : self.re = int(part_one) self.im = 0 else : raise ValueError("The form of complex numbers should be such as : 'a+bi' with a, b integers, floating numbers or fractions.") elif isinstance(a, (tuple,list)) and len(a) == 2 and b is None: # construction from 2-tuples or list self.re = a[0] self.im = a[1] elif isinstance(a, cplx) and b is None : # construction from cplx(complex) self.re = a.re self.im = a.im elif isinstance(a, (int, float, Q)) : # construction from integers, fractions and floating numbers self.re = a if b is None : self.im = 0 elif isinstance(b, (int, float, Q)) : self.im = b else : raise TypeError("Imaginary part sould be an integer, floating number or fraction .") else : raise TypeError("Invalid arguments! For details see help(cplx).") def __setattr__(self, n, v): if n not in ('re', 'im') : raise AttributeError("Invalid attribute.") if isinstance(v, (int, float, Q)) : object.__setattr__(self, n, v) else : raise TypeError("Illegal assignement.") def __delattr__(self, n): raise AttributeError("cplx instances are characterized by 're' and 'im' attributes, deleting them is impossible.") def __repr__(self): """Returns repr(self) in an elegant way.""" chain = '' if isinstance(self.re, Q) and self.re._numerator != 0 : if self.re._denominator != 1 : if self.re._numerator < 0 : chain += '-' chain += '({}/{})'.format(abs(self.re._numerator), self.re._denominator) else : chain += '{}'.format(int(self.re)) elif self.re != 0 : chain += '{}'.format(self.re) if self.re != 0 and self.im > 0 : chain += '+' elif self.im < 0 : chain += '-' if isinstance(self.im, Q) and self.im._numerator != 0 : if self.im._denominator != 1 : chain += '({}/{})'.format(abs(self.im._numerator), self.im._denominator) elif abs(self.im) != 1 : chain += '{}'.format(abs(int(self.im))) elif self.im != 0 and abs(self.im) != 1 : chain += '{}'.format(abs(self.im)) if self.im != 0 : chain += 'i' if chain == '' : chain = '0' return chain def __str__(self): """Returns str(self)""" return repr(self) def __int__(self): """Returns int(real part)""" return int(self.re) def __float__(self): """Returns float(real part)""" return float(self.re) def __bool__(self): """Returns self != 0""" return self != 0 def __pos__(self): """+self""" return self def __neg__(self): """-self""" return cplx(-self.re, -self.im) def __abs__(self): """Returns the absolute value if self is a real number. Returns its modulus if it is complex.""" if self.im == 0 : return cplx(abs(self.re)) else : return self.modul() # Comparaison block def __eq__(self, value): """self == value""" if isinstance(value, (_supported, cplx)) : value = cplx(value) return self.re == value.re and self.im == value.im else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __ne__(self, value): """self != 0""" return not self == value def __gt__(self, value): """self > value""" if isinstance(value, (_supported, cplx)) : value = cplx(value) if self.im == 0 and value.im == 0 : return self.re > value.re else : raise ValueError("Only real numbers are to be compared.") else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __ge__(self, value): """self >= value""" return self > value or self == value def __lt__(self, value): """self < value""" return not self >= value def __le__(self, value): """self <= value""" return not self > value # Operation block def __add__(self, value): """self + value""" if isinstance(value, (_supported, cplx)) : value = cplx(value) return cplx(self.re + value.re, self.im + value.im) else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __radd__(self, value): """value + self""" return self + value def __sub__(self, value): """self - value""" return self + (-value) def __rsub__(self, value): """value - self""" return -self + value def __mul__(self, value): """self * value""" if isinstance(value, (_supported, cplx)) : value = cplx(value) return cplx(self.re*value.re - self.im*value.im, self.re*value.im + self.im*value.re) else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __rmul__(self, value): """value * self""" return self * value def __pow__(self, value): """self**value""" if self.im == 0 : return cplx(self.re**value) elif isinstance(value, (_supported, cplx)) : value = cplx(value) if value == int(value): if value == 0 : return 1 z = self x = 1 while x < abs(value) : z *= self x += 1 if value > 0 : return z else : return 1/z else : return math.e**(value * (math.log(self.modul()) + self.arg()*cplx('i'))) else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __rpow__(self, value): """value**self""" if self.im == 0 : return value**self.re elif value == 0 : return 1 if self == 0 else 0 elif isinstance(value, (int, float, Q)) : return (value**self.re)*(math.cos(self.im*math.log(value)) + math.sin(self.im*math.log(value))*cplx('i')) else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __truediv__(self, value): """self/value : real and imaginary parts are left as fractions. Use c_float converter method to have floating numbers instead of fractions.""" if value == 0 : raise ZeroDivisionError elif isinstance(value, (_supported, cplx)) : value = cplx(value) return cplx(Q(self.re*value.re + self.im*value.im, value.re**2 + value.im**2), Q(self.im*value.re - self.re*value.im, value.re**2 + value.im**2)) else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __rtruediv__(self,value): """value/self""" if isinstance(value, (_supported, cplx)) : return cplx(value)/self else : raise TypeError("This type : {} is not supported for this operation.".format(type(value))) def __floordiv__(self, value): """self//value""" return (self/value).c_int() def __rfloordiv__(self, value): """value//self""" return (value/self).c_int() def __mod__(self, value): """self % value""" return self - (self//value)*value def __rmod__(self, value): """value % self""" return value - (value//self)*self def __divmod__(self, value): """divmod(self, value)""" return (self//value, self % value) def __rdivmod__(self, value): """divmod(value, self)""" return (value//self, value % self) # Converting methods for complex def c_int(self): """Converts real and imaginary parts into integers (returns a new object)""" return cplx(int(self.re), int(self.im)) def c_float(self): """Converts real and imaginary parts into floating numbers (returns a new object)""" return cplx(float(self.re), float(self.im)) def c_fract(self): """Converts real and imaginary parts into fractions (returns a new object)""" return cplx(Q.from_float(float(self.re)), Q.from_float(float(self.im))) # Useful methods def coord(self): """Returns the coordinates of a complex number in a tuple. a+bi -> (a,b)""" return (self.re, self.im) def conjugate(self): """Returns the conjugate of a complex number. a+bi -> a-bi""" return cplx(self.re, -self.im) def switch(self): """Returns a complex number with real part and imaginary part switched. a+bi -> b+ai""" return cplx(self.im, self.re) def modul(self): """Returns the modulus of the complex number""" return math.sqrt(self.re**2 + self.im**2) def arg(self): """Returns the argument of the complex number in radian""" if self != 0 : teta = math.acos(abs(self.re)/abs(self)) if self.re >= 0 and self.im > 0 : angle = teta elif self.re > 0 and self.im <= 0 : angle = -teta elif self.re < 0 and self.im >= 0 : angle = math.pi - teta elif self.re <= 0 and self.im < 0 : angle = -math.pi + teta else : raise ValueError("0 doesn't have an argument.") return angle def deg_arg(self): """Returns the argument of the complex number in degrees""" return math.degrees(self.arg()) def polar(self): """Returns the trigonometric form of a complex number -> str""" return "{}(cos({}) + sin({})i)".format(self.modul(), self.arg(), self.arg()) def factorise(self, value=1): """Returns a factorisation of a complex number by a value given (similar to divmod) -> str Example : (2i).factorise(i+1) >>> 2i = (i+1)(i+1)+0""" chain = "{} = ({})({})".format(self, value, self//value) if str(self%value)[0] == '-' : chain += "{}".format(self%value) else : chain += "+{}".format(self%value) return chain @classmethod def verify(cls, phrase) : """verify('a+bi') -> bool The argument must be provided in a string to verify whether it's a valid complex number or not. a and b can be integers, fractions(n/d), or floating numbers(with . or ,)""" if isinstance(phrase, str) : phrase = phrase.replace(" ", "") model_re = r"[+-]?[0-9]+([,./][0-9]+)?([+-]([0-9]+([,./][0-9]+)?[*]?)?i)?" # a real part and an optional imaginary part model_im = r"[+-]?([0-9]+([,./][0-9]+)?[*]?)?i([+-][0-9]+([,./][0-9]+)?)?" # an imaginary part and an optional real part return re.fullmatch(model_re, phrase) is not None or re.fullmatch(model_im, phrase) is not None else : raise TypeError("The complex number must be given in a string.") #---------------------------------------# i = cplx(0,1) # Most basic complex number #---------------------------------------#
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4