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