numbers.py 10 KB
Newer Older
1 2 3
# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.

4 5 6
"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141.

TODO: Fill out more detailed documentation on the operators."""
7

8
from abc import ABCMeta, abstractmethod
9

10
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
11 12 13 14 15 16 17

class Number(metaclass=ABCMeta):
    """All numbers inherit from this class.

    If you just want to check if an argument x is a number, without
    caring what kind, use isinstance(x, Number).
    """
18 19
    __slots__ = ()

20 21
    # Concrete numeric types must provide their own hash implementation
    __hash__ = None
22 23


Christian Heimes's avatar
Christian Heimes committed
24 25 26 27
## Notes on Decimal
## ----------------
## Decimal has all of the methods specified by the Real abc, but it should
## not be registered as a Real because decimals do not interoperate with
28 29 30
## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
## abstract reals are expected to interoperate (i.e. R1 + R2 should be
## expected to work if R1 and R2 are both Reals).
Christian Heimes's avatar
Christian Heimes committed
31

32 33 34 35 36 37 38 39 40 41 42
class Complex(Number):
    """Complex defines the operations that work on the builtin complex type.

    In short, those are: a conversion to complex, .real, .imag, +, -,
    *, /, abs(), .conjugate, ==, and !=.

    If it is given heterogenous arguments, and doesn't have special
    knowledge about them, it should fall back to the builtin complex
    type as described below.
    """

43 44
    __slots__ = ()

45 46
    @abstractmethod
    def __complex__(self):
47
        """Return a builtin complex instance. Called for complex(self)."""
48

49
    def __bool__(self):
50
        """True if self != 0. Called for bool(self)."""
51 52
        return self != 0

53 54
    @property
    @abstractmethod
55 56 57 58 59 60 61
    def real(self):
        """Retrieve the real component of this number.

        This should subclass Real.
        """
        raise NotImplementedError

62 63
    @property
    @abstractmethod
64
    def imag(self):
Benjamin Peterson's avatar
Benjamin Peterson committed
65
        """Retrieve the imaginary component of this number.
66 67 68 69 70 71 72

        This should subclass Real.
        """
        raise NotImplementedError

    @abstractmethod
    def __add__(self, other):
73
        """self + other"""
74 75 76 77
        raise NotImplementedError

    @abstractmethod
    def __radd__(self, other):
78
        """other + self"""
79 80 81 82
        raise NotImplementedError

    @abstractmethod
    def __neg__(self):
83
        """-self"""
84 85
        raise NotImplementedError

86
    @abstractmethod
87
    def __pos__(self):
88
        """+self"""
89
        raise NotImplementedError
90 91

    def __sub__(self, other):
92
        """self - other"""
93 94 95
        return self + -other

    def __rsub__(self, other):
96
        """other - self"""
97 98 99 100
        return -self + other

    @abstractmethod
    def __mul__(self, other):
101
        """self * other"""
102 103 104 105
        raise NotImplementedError

    @abstractmethod
    def __rmul__(self, other):
106
        """other * self"""
107 108
        raise NotImplementedError

109 110
    @abstractmethod
    def __truediv__(self, other):
111
        """self / other: Should promote to float when necessary."""
112 113 114 115
        raise NotImplementedError

    @abstractmethod
    def __rtruediv__(self, other):
116
        """other / self"""
117 118 119 120
        raise NotImplementedError

    @abstractmethod
    def __pow__(self, exponent):
121
        """self**exponent; should promote to float or complex when necessary."""
122 123 124 125
        raise NotImplementedError

    @abstractmethod
    def __rpow__(self, base):
126
        """base ** self"""
127 128 129 130
        raise NotImplementedError

    @abstractmethod
    def __abs__(self):
131
        """Returns the Real distance from 0. Called for abs(self)."""
132 133 134 135 136 137 138 139 140
        raise NotImplementedError

    @abstractmethod
    def conjugate(self):
        """(x+y*i).conjugate() returns (x-y*i)."""
        raise NotImplementedError

    @abstractmethod
    def __eq__(self, other):
141
        """self == other"""
142 143 144 145 146 147 148 149 150 151 152 153 154 155
        raise NotImplementedError

Complex.register(complex)


class Real(Complex):
    """To Complex, Real adds the operations that work on real numbers.

    In short, those are: a conversion to float, trunc(), divmod,
    %, <, <=, >, and >=.

    Real also provides defaults for the derived operations.
    """

156 157
    __slots__ = ()

158 159
    @abstractmethod
    def __float__(self):
160 161 162
        """Any Real can be converted to a native float object.

        Called for float(self)."""
163 164 165 166
        raise NotImplementedError

    @abstractmethod
    def __trunc__(self):
167
        """trunc(self): Truncates self to an Integral.
168 169

        Returns an Integral i such that:
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
          * i>0 iff self>0;
          * abs(i) <= abs(self);
          * for any Integral j satisfying the first two conditions,
            abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
        i.e. "truncate towards 0".
        """
        raise NotImplementedError

    @abstractmethod
    def __floor__(self):
        """Finds the greatest Integral <= self."""
        raise NotImplementedError

    @abstractmethod
    def __ceil__(self):
        """Finds the least Integral >= self."""
        raise NotImplementedError

    @abstractmethod
189
    def __round__(self, ndigits=None):
190 191 192 193
        """Rounds self to ndigits decimal places, defaulting to 0.

        If ndigits is omitted or None, returns an Integral, otherwise
        returns a Real. Rounds half toward even.
194 195 196 197
        """
        raise NotImplementedError

    def __divmod__(self, other):
198
        """divmod(self, other): The pair (self // other, self % other).
199 200 201 202 203 204 205

        Sometimes this can be computed faster than the pair of
        operations.
        """
        return (self // other, self % other)

    def __rdivmod__(self, other):
206
        """divmod(other, self): The pair (self // other, self % other).
207 208 209 210 211 212 213 214

        Sometimes this can be computed faster than the pair of
        operations.
        """
        return (other // self, other % self)

    @abstractmethod
    def __floordiv__(self, other):
215
        """self // other: The floor() of self/other."""
216 217 218 219
        raise NotImplementedError

    @abstractmethod
    def __rfloordiv__(self, other):
220
        """other // self: The floor() of other/self."""
221 222 223 224
        raise NotImplementedError

    @abstractmethod
    def __mod__(self, other):
225
        """self % other"""
226 227 228 229
        raise NotImplementedError

    @abstractmethod
    def __rmod__(self, other):
230
        """other % self"""
231 232 233 234
        raise NotImplementedError

    @abstractmethod
    def __lt__(self, other):
235 236 237
        """self < other

        < on Reals defines a total ordering, except perhaps for NaN."""
238 239
        raise NotImplementedError

240
    @abstractmethod
241
    def __le__(self, other):
242
        """self <= other"""
243 244 245 246
        raise NotImplementedError

    # Concrete implementations of Complex abstract methods.
    def __complex__(self):
247
        """complex(self) == complex(float(self), 0)"""
248 249 250 251
        return complex(float(self))

    @property
    def real(self):
252
        """Real numbers are their real component."""
253
        return +self
254 255 256

    @property
    def imag(self):
257
        """Real numbers have no imaginary component."""
258 259 260 261
        return 0

    def conjugate(self):
        """Conjugate is a no-op for Reals."""
262
        return +self
263 264 265 266

Real.register(float)


267
class Rational(Real):
268 269
    """.numerator and .denominator should be in lowest terms."""

270 271
    __slots__ = ()

272 273
    @property
    @abstractmethod
274 275 276
    def numerator(self):
        raise NotImplementedError

277 278
    @property
    @abstractmethod
279 280 281 282 283
    def denominator(self):
        raise NotImplementedError

    # Concrete implementation of Real's conversion to float.
    def __float__(self):
284 285 286 287 288 289 290
        """float(self) = self.numerator / self.denominator

        It's important that this conversion use the integer's "true"
        division rather than casting one side to float before dividing
        so that ratios of huge integers convert without overflowing.

        """
291 292 293 294 295 296
        return self.numerator / self.denominator


class Integral(Rational):
    """Integral adds a conversion to int and the bit-string operations."""

297 298
    __slots__ = ()

299 300
    @abstractmethod
    def __int__(self):
301
        """int(self)"""
302 303 304
        raise NotImplementedError

    def __index__(self):
305
        """Called whenever an index is needed, such as in slicing"""
306 307 308
        return int(self)

    @abstractmethod
309
    def __pow__(self, exponent, modulus=None):
310 311
        """self ** exponent % modulus, but maybe faster.

312 313 314 315
        Accept the modulus argument if you want to support the
        3-argument version of pow(). Raise a TypeError if exponent < 0
        or any argument isn't Integral. Otherwise, just implement the
        2-argument version described in Complex.
316 317 318 319 320
        """
        raise NotImplementedError

    @abstractmethod
    def __lshift__(self, other):
321
        """self << other"""
322 323 324 325
        raise NotImplementedError

    @abstractmethod
    def __rlshift__(self, other):
326
        """other << self"""
327 328 329 330
        raise NotImplementedError

    @abstractmethod
    def __rshift__(self, other):
331
        """self >> other"""
332 333 334 335
        raise NotImplementedError

    @abstractmethod
    def __rrshift__(self, other):
336
        """other >> self"""
337 338 339 340
        raise NotImplementedError

    @abstractmethod
    def __and__(self, other):
341
        """self & other"""
342 343 344 345
        raise NotImplementedError

    @abstractmethod
    def __rand__(self, other):
346
        """other & self"""
347 348 349 350
        raise NotImplementedError

    @abstractmethod
    def __xor__(self, other):
351
        """self ^ other"""
352 353 354 355
        raise NotImplementedError

    @abstractmethod
    def __rxor__(self, other):
356
        """other ^ self"""
357 358 359 360
        raise NotImplementedError

    @abstractmethod
    def __or__(self, other):
361
        """self | other"""
362 363 364 365
        raise NotImplementedError

    @abstractmethod
    def __ror__(self, other):
366
        """other | self"""
367 368 369 370
        raise NotImplementedError

    @abstractmethod
    def __invert__(self):
371
        """~self"""
372 373 374 375
        raise NotImplementedError

    # Concrete implementations of Rational and Real abstract methods.
    def __float__(self):
376
        """float(self) == float(int(self))"""
377 378 379 380
        return float(int(self))

    @property
    def numerator(self):
381
        """Integers are their own numerators."""
382
        return +self
383 384 385

    @property
    def denominator(self):
386
        """Integers have a denominator of 1."""
387 388 389
        return 1

Integral.register(int)