blob: 3c13290b1339657bfa77bb1622aec80b98806e6e [file] [log] [blame]
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +00001# Copyright 2007 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141.
5
6TODO: Fill out more detailed documentation on the operators."""
7
8from abc import ABCMeta, abstractmethod, abstractproperty
9
10__all__ = ["Number", "Exact", "Inexact",
11 "Complex", "Real", "Rational", "Integral",
12 ]
13
14
15class Number(object):
16 """All numbers inherit from this class.
17
18 If you just want to check if an argument x is a number, without
19 caring what kind, use isinstance(x, Number).
20 """
21 __metaclass__ = ABCMeta
22
23
24class Exact(Number):
25 """Operations on instances of this type are exact.
26
27 As long as the result of a homogenous operation is of the same
28 type, you can assume that it was computed exactly, and there are
29 no round-off errors. Laws like commutativity and associativity
30 hold.
31 """
32
33Exact.register(int)
34Exact.register(long)
35
36
37class Inexact(Number):
38 """Operations on instances of this type are inexact.
39
40 Given X, an instance of Inexact, it is possible that (X + -X) + 3
41 == 3, but X + (-X + 3) == 0. The exact form this error takes will
42 vary by type, but it's generally unsafe to compare this type for
43 equality.
44 """
45
46Inexact.register(complex)
47Inexact.register(float)
48# Inexact.register(decimal.Decimal)
49
50
51class Complex(Number):
52 """Complex defines the operations that work on the builtin complex type.
53
54 In short, those are: a conversion to complex, .real, .imag, +, -,
55 *, /, abs(), .conjugate, ==, and !=.
56
57 If it is given heterogenous arguments, and doesn't have special
58 knowledge about them, it should fall back to the builtin complex
59 type as described below.
60 """
61
62 @abstractmethod
63 def __complex__(self):
64 """Return a builtin complex instance. Called for complex(self)."""
65
66 def __bool__(self):
67 """True if self != 0. Called for bool(self)."""
68 return self != 0
69
70 @abstractproperty
71 def real(self):
72 """Retrieve the real component of this number.
73
74 This should subclass Real.
75 """
76 raise NotImplementedError
77
78 @abstractproperty
79 def imag(self):
80 """Retrieve the real component of this number.
81
82 This should subclass Real.
83 """
84 raise NotImplementedError
85
86 @abstractmethod
87 def __add__(self, other):
88 """self + other"""
89 raise NotImplementedError
90
91 @abstractmethod
92 def __radd__(self, other):
93 """other + self"""
94 raise NotImplementedError
95
96 @abstractmethod
97 def __neg__(self):
98 """-self"""
99 raise NotImplementedError
100
101 def __pos__(self):
102 """+self"""
103 raise NotImplementedError
104
105 def __sub__(self, other):
106 """self - other"""
107 return self + -other
108
109 def __rsub__(self, other):
110 """other - self"""
111 return -self + other
112
113 @abstractmethod
114 def __mul__(self, other):
115 """self * other"""
116 raise NotImplementedError
117
118 @abstractmethod
119 def __rmul__(self, other):
120 """other * self"""
121 raise NotImplementedError
122
123 @abstractmethod
124 def __div__(self, other):
125 """self / other; should promote to float or complex when necessary."""
126 raise NotImplementedError
127
128 @abstractmethod
129 def __rdiv__(self, other):
130 """other / self"""
131 raise NotImplementedError
132
133 @abstractmethod
134 def __pow__(self, exponent):
135 """self**exponent; should promote to float or complex when necessary."""
136 raise NotImplementedError
137
138 @abstractmethod
139 def __rpow__(self, base):
140 """base ** self"""
141 raise NotImplementedError
142
143 @abstractmethod
144 def __abs__(self):
145 """Returns the Real distance from 0. Called for abs(self)."""
146 raise NotImplementedError
147
148 @abstractmethod
149 def conjugate(self):
150 """(x+y*i).conjugate() returns (x-y*i)."""
151 raise NotImplementedError
152
153 @abstractmethod
154 def __eq__(self, other):
155 """self == other"""
156 raise NotImplementedError
157
158 # __ne__ is inherited from object and negates whatever __eq__ does.
159
160Complex.register(complex)
161
162
163class Real(Complex):
164 """To Complex, Real adds the operations that work on real numbers.
165
166 In short, those are: a conversion to float, trunc(), divmod,
167 %, <, <=, >, and >=.
168
169 Real also provides defaults for the derived operations.
170 """
171
172 @abstractmethod
173 def __float__(self):
174 """Any Real can be converted to a native float object.
175
176 Called for float(self)."""
177 raise NotImplementedError
178
179 @abstractmethod
180 def __trunc__(self):
181 """trunc(self): Truncates self to an Integral.
182
183 Returns an Integral i such that:
184 * i>0 iff self>0;
185 * abs(i) <= abs(self);
186 * for any Integral j satisfying the first two conditions,
187 abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
188 i.e. "truncate towards 0".
189 """
190 raise NotImplementedError
191
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000192 def __divmod__(self, other):
193 """divmod(self, other): The pair (self // other, self % other).
194
195 Sometimes this can be computed faster than the pair of
196 operations.
197 """
198 return (self // other, self % other)
199
200 def __rdivmod__(self, other):
201 """divmod(other, self): The pair (self // other, self % other).
202
203 Sometimes this can be computed faster than the pair of
204 operations.
205 """
206 return (other // self, other % self)
207
208 @abstractmethod
209 def __floordiv__(self, other):
210 """self // other: The floor() of self/other."""
211 raise NotImplementedError
212
213 @abstractmethod
214 def __rfloordiv__(self, other):
215 """other // self: The floor() of other/self."""
216 raise NotImplementedError
217
218 @abstractmethod
219 def __mod__(self, other):
220 """self % other"""
221 raise NotImplementedError
222
223 @abstractmethod
224 def __rmod__(self, other):
225 """other % self"""
226 raise NotImplementedError
227
228 @abstractmethod
229 def __lt__(self, other):
230 """self < other
231
232 < on Reals defines a total ordering, except perhaps for NaN."""
233 raise NotImplementedError
234
235 @abstractmethod
236 def __le__(self, other):
237 """self <= other"""
238 raise NotImplementedError
239
240 # Concrete implementations of Complex abstract methods.
241 def __complex__(self):
242 """complex(self) == complex(float(self), 0)"""
243 return complex(float(self))
244
245 @property
246 def real(self):
247 """Real numbers are their real component."""
248 return +self
249
250 @property
251 def imag(self):
252 """Real numbers have no imaginary component."""
253 return 0
254
255 def conjugate(self):
256 """Conjugate is a no-op for Reals."""
257 return +self
258
259Real.register(float)
260# Real.register(decimal.Decimal)
261
262
263class Rational(Real, Exact):
264 """.numerator and .denominator should be in lowest terms."""
265
266 @abstractproperty
267 def numerator(self):
268 raise NotImplementedError
269
270 @abstractproperty
271 def denominator(self):
272 raise NotImplementedError
273
274 # Concrete implementation of Real's conversion to float.
275 def __float__(self):
276 """float(self) = self.numerator / self.denominator"""
277 return self.numerator / self.denominator
278
279
280class Integral(Rational):
281 """Integral adds a conversion to long and the bit-string operations."""
282
283 @abstractmethod
284 def __long__(self):
285 """long(self)"""
286 raise NotImplementedError
287
288 def __index__(self):
289 """index(self)"""
290 return long(self)
291
292 @abstractmethod
293 def __pow__(self, exponent, modulus=None):
294 """self ** exponent % modulus, but maybe faster.
295
296 Accept the modulus argument if you want to support the
297 3-argument version of pow(). Raise a TypeError if exponent < 0
298 or any argument isn't Integral. Otherwise, just implement the
299 2-argument version described in Complex.
300 """
301 raise NotImplementedError
302
303 @abstractmethod
304 def __lshift__(self, other):
305 """self << other"""
306 raise NotImplementedError
307
308 @abstractmethod
309 def __rlshift__(self, other):
310 """other << self"""
311 raise NotImplementedError
312
313 @abstractmethod
314 def __rshift__(self, other):
315 """self >> other"""
316 raise NotImplementedError
317
318 @abstractmethod
319 def __rrshift__(self, other):
320 """other >> self"""
321 raise NotImplementedError
322
323 @abstractmethod
324 def __and__(self, other):
325 """self & other"""
326 raise NotImplementedError
327
328 @abstractmethod
329 def __rand__(self, other):
330 """other & self"""
331 raise NotImplementedError
332
333 @abstractmethod
334 def __xor__(self, other):
335 """self ^ other"""
336 raise NotImplementedError
337
338 @abstractmethod
339 def __rxor__(self, other):
340 """other ^ self"""
341 raise NotImplementedError
342
343 @abstractmethod
344 def __or__(self, other):
345 """self | other"""
346 raise NotImplementedError
347
348 @abstractmethod
349 def __ror__(self, other):
350 """other | self"""
351 raise NotImplementedError
352
353 @abstractmethod
354 def __invert__(self):
355 """~self"""
356 raise NotImplementedError
357
358 # Concrete implementations of Rational and Real abstract methods.
359 def __float__(self):
360 """float(self) == float(long(self))"""
361 return float(long(self))
362
363 @property
364 def numerator(self):
365 """Integers are their own numerators."""
366 return +self
367
368 @property
369 def denominator(self):
370 """Integers have a denominator of 1."""
371 return 1
372
373Integral.register(int)
374Integral.register(long)