blob: d23fa34eddce842343cc3d6592fc795afb109c5a [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
192 @abstractmethod
193 def __floor__(self):
194 """Finds the greatest Integral <= self."""
195 raise NotImplementedError
196
197 @abstractmethod
198 def __ceil__(self):
199 """Finds the least Integral >= self."""
200 raise NotImplementedError
201
202 @abstractmethod
203 def __round__(self, ndigits=None):
204 """Rounds self to ndigits decimal places, defaulting to 0.
205
206 If ndigits is omitted or None, returns an Integral, otherwise
207 returns a Real. Rounds half toward even.
208 """
209 raise NotImplementedError
210
211 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)