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