blob: 4728f99a59007688bb0ab8b41cf70d2277ae6aed [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
Raymond Hettinger48688d82008-02-11 22:53:01 +000052## Notes on Decimal and how relates to the numeric tower
53## -----------------------------------------------------
54## Decimal is Real except that it does not support the real and imag properties
55## or the conjugate() and complex() methods. If those get defined at some
56## point, they cannot use the default implementation which would be sensitive
57## to decimal.Context and could produce different answers at different times.
58##
59## Decimal has some of the characteristics of Integrals. It provides
60## logical operations but not as operators. The logical operations only apply
61## to a subset of decimals (those that are non-negative, have a zero exponent,
62## and have digits that are only 0 or 1). It does provide __long__() and
63## a three argument form of __pow__ that includes exactness guarantees.
64## It does not provide an __index__() method.
65##
66## Depending on context, decimal operations may be exact or inexact.
67##
68## When decimal is run in a context with small precision and automatic rounding,
69## it is Inexact. See the "Floating point notes" section of the decimal docs
70## for an example of losing the associative and distributive properties of
71## addition.
72##
73## When decimal is used for high precision integer arithmetic, it is Exact.
74## When the decimal used as fixed-point, it is Exact.
75## When it is run with sufficient precision, it is Exact.
76## When the decimal.Inexact trap is set, decimal operations are Exact.
77## For an example, see the float_to_decimal() recipe in the "Decimal FAQ"
78## section of the docs -- it shows an how traps are used in conjunction
79## with variable precision to reliably achieve exact results.
80
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +000081class Complex(Number):
82 """Complex defines the operations that work on the builtin complex type.
83
84 In short, those are: a conversion to complex, .real, .imag, +, -,
85 *, /, abs(), .conjugate, ==, and !=.
86
87 If it is given heterogenous arguments, and doesn't have special
88 knowledge about them, it should fall back to the builtin complex
89 type as described below.
90 """
91
92 @abstractmethod
93 def __complex__(self):
94 """Return a builtin complex instance. Called for complex(self)."""
95
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000096 # Will be __bool__ in 3.0.
97 def __nonzero__(self):
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +000098 """True if self != 0. Called for bool(self)."""
99 return self != 0
100
101 @abstractproperty
102 def real(self):
103 """Retrieve the real component of this number.
104
105 This should subclass Real.
106 """
107 raise NotImplementedError
108
109 @abstractproperty
110 def imag(self):
111 """Retrieve the real component of this number.
112
113 This should subclass Real.
114 """
115 raise NotImplementedError
116
117 @abstractmethod
118 def __add__(self, other):
119 """self + other"""
120 raise NotImplementedError
121
122 @abstractmethod
123 def __radd__(self, other):
124 """other + self"""
125 raise NotImplementedError
126
127 @abstractmethod
128 def __neg__(self):
129 """-self"""
130 raise NotImplementedError
131
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000132 @abstractmethod
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000133 def __pos__(self):
134 """+self"""
135 raise NotImplementedError
136
137 def __sub__(self, other):
138 """self - other"""
139 return self + -other
140
141 def __rsub__(self, other):
142 """other - self"""
143 return -self + other
144
145 @abstractmethod
146 def __mul__(self, other):
147 """self * other"""
148 raise NotImplementedError
149
150 @abstractmethod
151 def __rmul__(self, other):
152 """other * self"""
153 raise NotImplementedError
154
155 @abstractmethod
156 def __div__(self, other):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000157 """self / other without __future__ division
158
159 May promote to float.
160 """
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000161 raise NotImplementedError
162
163 @abstractmethod
164 def __rdiv__(self, other):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000165 """other / self without __future__ division"""
166 raise NotImplementedError
167
168 @abstractmethod
169 def __truediv__(self, other):
170 """self / other with __future__ division.
171
172 Should promote to float when necessary.
173 """
174 raise NotImplementedError
175
176 @abstractmethod
177 def __rtruediv__(self, other):
178 """other / self with __future__ division"""
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000179 raise NotImplementedError
180
181 @abstractmethod
182 def __pow__(self, exponent):
183 """self**exponent; should promote to float or complex when necessary."""
184 raise NotImplementedError
185
186 @abstractmethod
187 def __rpow__(self, base):
188 """base ** self"""
189 raise NotImplementedError
190
191 @abstractmethod
192 def __abs__(self):
193 """Returns the Real distance from 0. Called for abs(self)."""
194 raise NotImplementedError
195
196 @abstractmethod
197 def conjugate(self):
198 """(x+y*i).conjugate() returns (x-y*i)."""
199 raise NotImplementedError
200
201 @abstractmethod
202 def __eq__(self, other):
203 """self == other"""
204 raise NotImplementedError
205
Jeffrey Yasskin27d33942008-02-08 06:45:40 +0000206 def __ne__(self, other):
207 """self != other"""
208 # The default __ne__ doesn't negate __eq__ until 3.0.
209 return not (self == other)
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000210
211Complex.register(complex)
212
213
214class Real(Complex):
215 """To Complex, Real adds the operations that work on real numbers.
216
217 In short, those are: a conversion to float, trunc(), divmod,
218 %, <, <=, >, and >=.
219
220 Real also provides defaults for the derived operations.
221 """
222
223 @abstractmethod
224 def __float__(self):
225 """Any Real can be converted to a native float object.
226
227 Called for float(self)."""
228 raise NotImplementedError
229
230 @abstractmethod
231 def __trunc__(self):
232 """trunc(self): Truncates self to an Integral.
233
234 Returns an Integral i such that:
235 * i>0 iff self>0;
236 * abs(i) <= abs(self);
237 * for any Integral j satisfying the first two conditions,
238 abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
239 i.e. "truncate towards 0".
240 """
241 raise NotImplementedError
242
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000243 def __divmod__(self, other):
244 """divmod(self, other): The pair (self // other, self % other).
245
246 Sometimes this can be computed faster than the pair of
247 operations.
248 """
249 return (self // other, self % other)
250
251 def __rdivmod__(self, other):
252 """divmod(other, self): The pair (self // other, self % other).
253
254 Sometimes this can be computed faster than the pair of
255 operations.
256 """
257 return (other // self, other % self)
258
259 @abstractmethod
260 def __floordiv__(self, other):
261 """self // other: The floor() of self/other."""
262 raise NotImplementedError
263
264 @abstractmethod
265 def __rfloordiv__(self, other):
266 """other // self: The floor() of other/self."""
267 raise NotImplementedError
268
269 @abstractmethod
270 def __mod__(self, other):
271 """self % other"""
272 raise NotImplementedError
273
274 @abstractmethod
275 def __rmod__(self, other):
276 """other % self"""
277 raise NotImplementedError
278
279 @abstractmethod
280 def __lt__(self, other):
281 """self < other
282
283 < on Reals defines a total ordering, except perhaps for NaN."""
284 raise NotImplementedError
285
286 @abstractmethod
287 def __le__(self, other):
288 """self <= other"""
289 raise NotImplementedError
290
291 # Concrete implementations of Complex abstract methods.
292 def __complex__(self):
293 """complex(self) == complex(float(self), 0)"""
294 return complex(float(self))
295
296 @property
297 def real(self):
298 """Real numbers are their real component."""
299 return +self
300
301 @property
302 def imag(self):
303 """Real numbers have no imaginary component."""
304 return 0
305
306 def conjugate(self):
307 """Conjugate is a no-op for Reals."""
308 return +self
309
310Real.register(float)
311# Real.register(decimal.Decimal)
312
313
314class Rational(Real, Exact):
315 """.numerator and .denominator should be in lowest terms."""
316
317 @abstractproperty
318 def numerator(self):
319 raise NotImplementedError
320
321 @abstractproperty
322 def denominator(self):
323 raise NotImplementedError
324
325 # Concrete implementation of Real's conversion to float.
326 def __float__(self):
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000327 """float(self) = self.numerator / self.denominator
328
329 It's important that this conversion use the integer's "true"
330 division rather than casting one side to float before dividing
331 so that ratios of huge integers convert without overflowing.
332
333 """
Jeffrey Yasskin2f3c16b2008-01-03 02:21:52 +0000334 return self.numerator / self.denominator
335
336
337class Integral(Rational):
338 """Integral adds a conversion to long and the bit-string operations."""
339
340 @abstractmethod
341 def __long__(self):
342 """long(self)"""
343 raise NotImplementedError
344
345 def __index__(self):
346 """index(self)"""
347 return long(self)
348
349 @abstractmethod
350 def __pow__(self, exponent, modulus=None):
351 """self ** exponent % modulus, but maybe faster.
352
353 Accept the modulus argument if you want to support the
354 3-argument version of pow(). Raise a TypeError if exponent < 0
355 or any argument isn't Integral. Otherwise, just implement the
356 2-argument version described in Complex.
357 """
358 raise NotImplementedError
359
360 @abstractmethod
361 def __lshift__(self, other):
362 """self << other"""
363 raise NotImplementedError
364
365 @abstractmethod
366 def __rlshift__(self, other):
367 """other << self"""
368 raise NotImplementedError
369
370 @abstractmethod
371 def __rshift__(self, other):
372 """self >> other"""
373 raise NotImplementedError
374
375 @abstractmethod
376 def __rrshift__(self, other):
377 """other >> self"""
378 raise NotImplementedError
379
380 @abstractmethod
381 def __and__(self, other):
382 """self & other"""
383 raise NotImplementedError
384
385 @abstractmethod
386 def __rand__(self, other):
387 """other & self"""
388 raise NotImplementedError
389
390 @abstractmethod
391 def __xor__(self, other):
392 """self ^ other"""
393 raise NotImplementedError
394
395 @abstractmethod
396 def __rxor__(self, other):
397 """other ^ self"""
398 raise NotImplementedError
399
400 @abstractmethod
401 def __or__(self, other):
402 """self | other"""
403 raise NotImplementedError
404
405 @abstractmethod
406 def __ror__(self, other):
407 """other | self"""
408 raise NotImplementedError
409
410 @abstractmethod
411 def __invert__(self):
412 """~self"""
413 raise NotImplementedError
414
415 # Concrete implementations of Rational and Real abstract methods.
416 def __float__(self):
417 """float(self) == float(long(self))"""
418 return float(long(self))
419
420 @property
421 def numerator(self):
422 """Integers are their own numerators."""
423 return +self
424
425 @property
426 def denominator(self):
427 """Integers have a denominator of 1."""
428 return 1
429
430Integral.register(int)
431Integral.register(long)