symbian-qemu-0.9.1-12/python-2.6.1/Demo/classes/Complex.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 # Complex numbers
       
     2 # ---------------
       
     3 
       
     4 # [Now that Python has a complex data type built-in, this is not very
       
     5 # useful, but it's still a nice example class]
       
     6 
       
     7 # This module represents complex numbers as instances of the class Complex.
       
     8 # A Complex instance z has two data attribues, z.re (the real part) and z.im
       
     9 # (the imaginary part).  In fact, z.re and z.im can have any value -- all
       
    10 # arithmetic operators work regardless of the type of z.re and z.im (as long
       
    11 # as they support numerical operations).
       
    12 #
       
    13 # The following functions exist (Complex is actually a class):
       
    14 # Complex([re [,im]) -> creates a complex number from a real and an imaginary part
       
    15 # IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
       
    16 # ToComplex(z) -> a complex number equal to z; z itself if IsComplex(z) is true
       
    17 #                 if z is a tuple(re, im) it will also be converted
       
    18 # PolarToComplex([r [,phi [,fullcircle]]]) ->
       
    19 #       the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
       
    20 #       (r and phi default to 0)
       
    21 # exp(z) -> returns the complex exponential of z. Equivalent to pow(math.e,z).
       
    22 #
       
    23 # Complex numbers have the following methods:
       
    24 # z.abs() -> absolute value of z
       
    25 # z.radius() == z.abs()
       
    26 # z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
       
    27 # z.phi([fullcircle]) == z.angle(fullcircle)
       
    28 #
       
    29 # These standard functions and unary operators accept complex arguments:
       
    30 # abs(z)
       
    31 # -z
       
    32 # +z
       
    33 # not z
       
    34 # repr(z) == `z`
       
    35 # str(z)
       
    36 # hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
       
    37 #            the result equals hash(z.re)
       
    38 # Note that hex(z) and oct(z) are not defined.
       
    39 #
       
    40 # These conversions accept complex arguments only if their imaginary part is zero:
       
    41 # int(z)
       
    42 # long(z)
       
    43 # float(z)
       
    44 #
       
    45 # The following operators accept two complex numbers, or one complex number
       
    46 # and one real number (int, long or float):
       
    47 # z1 + z2
       
    48 # z1 - z2
       
    49 # z1 * z2
       
    50 # z1 / z2
       
    51 # pow(z1, z2)
       
    52 # cmp(z1, z2)
       
    53 # Note that z1 % z2 and divmod(z1, z2) are not defined,
       
    54 # nor are shift and mask operations.
       
    55 #
       
    56 # The standard module math does not support complex numbers.
       
    57 # The cmath modules should be used instead.
       
    58 #
       
    59 # Idea:
       
    60 # add a class Polar(r, phi) and mixed-mode arithmetic which
       
    61 # chooses the most appropriate type for the result:
       
    62 # Complex for +,-,cmp
       
    63 # Polar   for *,/,pow
       
    64 
       
    65 import math
       
    66 import sys
       
    67 
       
    68 twopi = math.pi*2.0
       
    69 halfpi = math.pi/2.0
       
    70 
       
    71 def IsComplex(obj):
       
    72     return hasattr(obj, 're') and hasattr(obj, 'im')
       
    73 
       
    74 def ToComplex(obj):
       
    75     if IsComplex(obj):
       
    76         return obj
       
    77     elif isinstance(obj, tuple):
       
    78         return Complex(*obj)
       
    79     else:
       
    80         return Complex(obj)
       
    81 
       
    82 def PolarToComplex(r = 0, phi = 0, fullcircle = twopi):
       
    83     phi = phi * (twopi / fullcircle)
       
    84     return Complex(math.cos(phi)*r, math.sin(phi)*r)
       
    85 
       
    86 def Re(obj):
       
    87     if IsComplex(obj):
       
    88         return obj.re
       
    89     return obj
       
    90 
       
    91 def Im(obj):
       
    92     if IsComplex(obj):
       
    93         return obj.im
       
    94     return 0
       
    95 
       
    96 class Complex:
       
    97 
       
    98     def __init__(self, re=0, im=0):
       
    99         _re = 0
       
   100         _im = 0
       
   101         if IsComplex(re):
       
   102             _re = re.re
       
   103             _im = re.im
       
   104         else:
       
   105             _re = re
       
   106         if IsComplex(im):
       
   107             _re = _re - im.im
       
   108             _im = _im + im.re
       
   109         else:
       
   110             _im = _im + im
       
   111         # this class is immutable, so setting self.re directly is
       
   112         # not possible.
       
   113         self.__dict__['re'] = _re
       
   114         self.__dict__['im'] = _im
       
   115 
       
   116     def __setattr__(self, name, value):
       
   117         raise TypeError, 'Complex numbers are immutable'
       
   118 
       
   119     def __hash__(self):
       
   120         if not self.im:
       
   121             return hash(self.re)
       
   122         return hash((self.re, self.im))
       
   123 
       
   124     def __repr__(self):
       
   125         if not self.im:
       
   126             return 'Complex(%r)' % (self.re,)
       
   127         else:
       
   128             return 'Complex(%r, %r)' % (self.re, self.im)
       
   129 
       
   130     def __str__(self):
       
   131         if not self.im:
       
   132             return repr(self.re)
       
   133         else:
       
   134             return 'Complex(%r, %r)' % (self.re, self.im)
       
   135 
       
   136     def __neg__(self):
       
   137         return Complex(-self.re, -self.im)
       
   138 
       
   139     def __pos__(self):
       
   140         return self
       
   141 
       
   142     def __abs__(self):
       
   143         return math.hypot(self.re, self.im)
       
   144 
       
   145     def __int__(self):
       
   146         if self.im:
       
   147             raise ValueError, "can't convert Complex with nonzero im to int"
       
   148         return int(self.re)
       
   149 
       
   150     def __long__(self):
       
   151         if self.im:
       
   152             raise ValueError, "can't convert Complex with nonzero im to long"
       
   153         return long(self.re)
       
   154 
       
   155     def __float__(self):
       
   156         if self.im:
       
   157             raise ValueError, "can't convert Complex with nonzero im to float"
       
   158         return float(self.re)
       
   159 
       
   160     def __cmp__(self, other):
       
   161         other = ToComplex(other)
       
   162         return cmp((self.re, self.im), (other.re, other.im))
       
   163 
       
   164     def __rcmp__(self, other):
       
   165         other = ToComplex(other)
       
   166         return cmp(other, self)
       
   167 
       
   168     def __nonzero__(self):
       
   169         return not (self.re == self.im == 0)
       
   170 
       
   171     abs = radius = __abs__
       
   172 
       
   173     def angle(self, fullcircle = twopi):
       
   174         return (fullcircle/twopi) * ((halfpi - math.atan2(self.re, self.im)) % twopi)
       
   175 
       
   176     phi = angle
       
   177 
       
   178     def __add__(self, other):
       
   179         other = ToComplex(other)
       
   180         return Complex(self.re + other.re, self.im + other.im)
       
   181 
       
   182     __radd__ = __add__
       
   183 
       
   184     def __sub__(self, other):
       
   185         other = ToComplex(other)
       
   186         return Complex(self.re - other.re, self.im - other.im)
       
   187 
       
   188     def __rsub__(self, other):
       
   189         other = ToComplex(other)
       
   190         return other - self
       
   191 
       
   192     def __mul__(self, other):
       
   193         other = ToComplex(other)
       
   194         return Complex(self.re*other.re - self.im*other.im,
       
   195                        self.re*other.im + self.im*other.re)
       
   196 
       
   197     __rmul__ = __mul__
       
   198 
       
   199     def __div__(self, other):
       
   200         other = ToComplex(other)
       
   201         d = float(other.re*other.re + other.im*other.im)
       
   202         if not d: raise ZeroDivisionError, 'Complex division'
       
   203         return Complex((self.re*other.re + self.im*other.im) / d,
       
   204                        (self.im*other.re - self.re*other.im) / d)
       
   205 
       
   206     def __rdiv__(self, other):
       
   207         other = ToComplex(other)
       
   208         return other / self
       
   209 
       
   210     def __pow__(self, n, z=None):
       
   211         if z is not None:
       
   212             raise TypeError, 'Complex does not support ternary pow()'
       
   213         if IsComplex(n):
       
   214             if n.im:
       
   215                 if self.im: raise TypeError, 'Complex to the Complex power'
       
   216                 else: return exp(math.log(self.re)*n)
       
   217             n = n.re
       
   218         r = pow(self.abs(), n)
       
   219         phi = n*self.angle()
       
   220         return Complex(math.cos(phi)*r, math.sin(phi)*r)
       
   221 
       
   222     def __rpow__(self, base):
       
   223         base = ToComplex(base)
       
   224         return pow(base, self)
       
   225 
       
   226 def exp(z):
       
   227     r = math.exp(z.re)
       
   228     return Complex(math.cos(z.im)*r,math.sin(z.im)*r)
       
   229 
       
   230 
       
   231 def checkop(expr, a, b, value, fuzz = 1e-6):
       
   232     print '       ', a, 'and', b,
       
   233     try:
       
   234         result = eval(expr)
       
   235     except:
       
   236         result = sys.exc_type
       
   237     print '->', result
       
   238     if isinstance(result, str) or isinstance(value, str):
       
   239         ok = (result == value)
       
   240     else:
       
   241         ok = abs(result - value) <= fuzz
       
   242     if not ok:
       
   243         print '!!\t!!\t!! should be', value, 'diff', abs(result - value)
       
   244 
       
   245 def test():
       
   246     print 'test constructors'
       
   247     constructor_test = (
       
   248         # "expect" is an array [re,im] "got" the Complex.
       
   249             ( (0,0), Complex() ),
       
   250             ( (0,0), Complex() ),
       
   251             ( (1,0), Complex(1) ),
       
   252             ( (0,1), Complex(0,1) ),
       
   253             ( (1,2), Complex(Complex(1,2)) ),
       
   254             ( (1,3), Complex(Complex(1,2),1) ),
       
   255             ( (0,0), Complex(0,Complex(0,0)) ),
       
   256             ( (3,4), Complex(3,Complex(4)) ),
       
   257             ( (-1,3), Complex(1,Complex(3,2)) ),
       
   258             ( (-7,6), Complex(Complex(1,2),Complex(4,8)) ) )
       
   259     cnt = [0,0]
       
   260     for t in constructor_test:
       
   261         cnt[0] += 1
       
   262         if ((t[0][0]!=t[1].re)or(t[0][1]!=t[1].im)):
       
   263             print "        expected", t[0], "got", t[1]
       
   264             cnt[1] += 1
       
   265     print "  ", cnt[1], "of", cnt[0], "tests failed"
       
   266     # test operators
       
   267     testsuite = {
       
   268             'a+b': [
       
   269                     (1, 10, 11),
       
   270                     (1, Complex(0,10), Complex(1,10)),
       
   271                     (Complex(0,10), 1, Complex(1,10)),
       
   272                     (Complex(0,10), Complex(1), Complex(1,10)),
       
   273                     (Complex(1), Complex(0,10), Complex(1,10)),
       
   274             ],
       
   275             'a-b': [
       
   276                     (1, 10, -9),
       
   277                     (1, Complex(0,10), Complex(1,-10)),
       
   278                     (Complex(0,10), 1, Complex(-1,10)),
       
   279                     (Complex(0,10), Complex(1), Complex(-1,10)),
       
   280                     (Complex(1), Complex(0,10), Complex(1,-10)),
       
   281             ],
       
   282             'a*b': [
       
   283                     (1, 10, 10),
       
   284                     (1, Complex(0,10), Complex(0, 10)),
       
   285                     (Complex(0,10), 1, Complex(0,10)),
       
   286                     (Complex(0,10), Complex(1), Complex(0,10)),
       
   287                     (Complex(1), Complex(0,10), Complex(0,10)),
       
   288             ],
       
   289             'a/b': [
       
   290                     (1., 10, 0.1),
       
   291                     (1, Complex(0,10), Complex(0, -0.1)),
       
   292                     (Complex(0, 10), 1, Complex(0, 10)),
       
   293                     (Complex(0, 10), Complex(1), Complex(0, 10)),
       
   294                     (Complex(1), Complex(0,10), Complex(0, -0.1)),
       
   295             ],
       
   296             'pow(a,b)': [
       
   297                     (1, 10, 1),
       
   298                     (1, Complex(0,10), 1),
       
   299                     (Complex(0,10), 1, Complex(0,10)),
       
   300                     (Complex(0,10), Complex(1), Complex(0,10)),
       
   301                     (Complex(1), Complex(0,10), 1),
       
   302                     (2, Complex(4,0), 16),
       
   303             ],
       
   304             'cmp(a,b)': [
       
   305                     (1, 10, -1),
       
   306                     (1, Complex(0,10), 1),
       
   307                     (Complex(0,10), 1, -1),
       
   308                     (Complex(0,10), Complex(1), -1),
       
   309                     (Complex(1), Complex(0,10), 1),
       
   310             ],
       
   311     }
       
   312     for expr in sorted(testsuite):
       
   313         print expr + ':'
       
   314         t = (expr,)
       
   315         for item in testsuite[expr]:
       
   316             checkop(*(t+item))
       
   317 
       
   318 
       
   319 if __name__ == '__main__':
       
   320     test()