numbers.py 10.2 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
        raise NotImplementedError

Christian Heimes's avatar
Christian Heimes committed
144 145 146 147
    def __ne__(self, other):
        """self != other"""
        # The default __ne__ doesn't negate __eq__ until 3.0.
        return not (self == other)
148 149 150 151 152 153 154 155 156 157 158 159 160

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.
    """

161 162
    __slots__ = ()

163 164
    @abstractmethod
    def __float__(self):
165 166 167
        """Any Real can be converted to a native float object.

        Called for float(self)."""
168 169 170 171
        raise NotImplementedError

    @abstractmethod
    def __trunc__(self):
172
        """trunc(self): Truncates self to an Integral.
173 174

        Returns an Integral i such that:
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
          * 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
194
    def __round__(self, ndigits=None):
195 196 197 198
        """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.
199 200 201 202
        """
        raise NotImplementedError

    def __divmod__(self, other):
203
        """divmod(self, other): The pair (self // other, self % other).
204 205 206 207 208 209 210

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

    def __rdivmod__(self, other):
211
        """divmod(other, self): The pair (self // other, self % other).
212 213 214 215 216 217 218 219

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

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

    @abstractmethod
    def __rfloordiv__(self, other):
225
        """other // self: The floor() of other/self."""
226 227 228 229
        raise NotImplementedError

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

    @abstractmethod
    def __rmod__(self, other):
235
        """other % self"""
236 237 238 239
        raise NotImplementedError

    @abstractmethod
    def __lt__(self, other):
240 241 242
        """self < other

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

245
    @abstractmethod
246
    def __le__(self, other):
247
        """self <= other"""
248 249 250 251
        raise NotImplementedError

    # Concrete implementations of Complex abstract methods.
    def __complex__(self):
252
        """complex(self) == complex(float(self), 0)"""
253 254 255 256
        return complex(float(self))

    @property
    def real(self):
257
        """Real numbers are their real component."""
258
        return +self
259 260 261

    @property
    def imag(self):
262
        """Real numbers have no imaginary component."""
263 264 265 266
        return 0

    def conjugate(self):
        """Conjugate is a no-op for Reals."""
267
        return +self
268 269 270 271

Real.register(float)


272
class Rational(Real):
273 274
    """.numerator and .denominator should be in lowest terms."""

275 276
    __slots__ = ()

277 278
    @property
    @abstractmethod
279 280 281
    def numerator(self):
        raise NotImplementedError

282 283
    @property
    @abstractmethod
284 285 286 287 288
    def denominator(self):
        raise NotImplementedError

    # Concrete implementation of Real's conversion to float.
    def __float__(self):
289 290 291 292 293 294 295
        """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.

        """
296 297 298 299 300 301
        return self.numerator / self.denominator


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

302 303
    __slots__ = ()

304 305
    @abstractmethod
    def __int__(self):
306
        """int(self)"""
307 308 309
        raise NotImplementedError

    def __index__(self):
310
        """Called whenever an index is needed, such as in slicing"""
311 312 313
        return int(self)

    @abstractmethod
314
    def __pow__(self, exponent, modulus=None):
315 316
        """self ** exponent % modulus, but maybe faster.

317 318 319 320
        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.
321 322 323 324 325
        """
        raise NotImplementedError

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

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

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

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

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

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

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

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

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

    @abstractmethod
    def __ror__(self, other):
371
        """other | self"""
372 373 374 375
        raise NotImplementedError

    @abstractmethod
    def __invert__(self):
376
        """~self"""
377 378 379 380
        raise NotImplementedError

    # Concrete implementations of Rational and Real abstract methods.
    def __float__(self):
381
        """float(self) == float(int(self))"""
382 383 384 385
        return float(int(self))

    @property
    def numerator(self):
386
        """Integers are their own numerators."""
387
        return +self
388 389 390

    @property
    def denominator(self):
391
        """Integers have a denominator of 1."""
392 393 394
        return 1

Integral.register(int)