diff options
author | Jeffrey Yasskin <jyasskin@gmail.com> | 2008-01-03 02:21:52 (GMT) |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@gmail.com> | 2008-01-03 02:21:52 (GMT) |
commit | 2f3c16be73a8562d357b9b13bbb8088e275840a7 (patch) | |
tree | 5334d4bd6c8b6456da10c0be232fb8bf95b1aca7 /Lib/numbers.py | |
parent | 27edd829d7673a642cf5b37c3011454ec33cb715 (diff) | |
download | cpython-2f3c16be73a8562d357b9b13bbb8088e275840a7.zip cpython-2f3c16be73a8562d357b9b13bbb8088e275840a7.tar.gz cpython-2f3c16be73a8562d357b9b13bbb8088e275840a7.tar.bz2 |
Backport PEP 3141 from the py3k branch to the trunk. This includes r50877 (just
the complex_pow part), r56649, r56652, r56715, r57296, r57302, r57359, r57361,
r57372, r57738, r57739, r58017, r58039, r58040, and r59390, and new
documentation. The only significant difference is that round(x) returns a float
to preserve backward-compatibility. See http://bugs.python.org/issue1689.
Diffstat (limited to 'Lib/numbers.py')
-rw-r--r-- | Lib/numbers.py | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/Lib/numbers.py b/Lib/numbers.py new file mode 100644 index 0000000..d23fa34 --- /dev/null +++ b/Lib/numbers.py @@ -0,0 +1,393 @@ +# Copyright 2007 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141. + +TODO: Fill out more detailed documentation on the operators.""" + +from abc import ABCMeta, abstractmethod, abstractproperty + +__all__ = ["Number", "Exact", "Inexact", + "Complex", "Real", "Rational", "Integral", + ] + + +class Number(object): + """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). + """ + __metaclass__ = ABCMeta + + +class Exact(Number): + """Operations on instances of this type are exact. + + As long as the result of a homogenous operation is of the same + type, you can assume that it was computed exactly, and there are + no round-off errors. Laws like commutativity and associativity + hold. + """ + +Exact.register(int) +Exact.register(long) + + +class Inexact(Number): + """Operations on instances of this type are inexact. + + Given X, an instance of Inexact, it is possible that (X + -X) + 3 + == 3, but X + (-X + 3) == 0. The exact form this error takes will + vary by type, but it's generally unsafe to compare this type for + equality. + """ + +Inexact.register(complex) +Inexact.register(float) +# Inexact.register(decimal.Decimal) + + +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. + """ + + @abstractmethod + def __complex__(self): + """Return a builtin complex instance. Called for complex(self).""" + + def __bool__(self): + """True if self != 0. Called for bool(self).""" + return self != 0 + + @abstractproperty + def real(self): + """Retrieve the real component of this number. + + This should subclass Real. + """ + raise NotImplementedError + + @abstractproperty + def imag(self): + """Retrieve the real component of this number. + + This should subclass Real. + """ + raise NotImplementedError + + @abstractmethod + def __add__(self, other): + """self + other""" + raise NotImplementedError + + @abstractmethod + def __radd__(self, other): + """other + self""" + raise NotImplementedError + + @abstractmethod + def __neg__(self): + """-self""" + raise NotImplementedError + + def __pos__(self): + """+self""" + raise NotImplementedError + + def __sub__(self, other): + """self - other""" + return self + -other + + def __rsub__(self, other): + """other - self""" + return -self + other + + @abstractmethod + def __mul__(self, other): + """self * other""" + raise NotImplementedError + + @abstractmethod + def __rmul__(self, other): + """other * self""" + raise NotImplementedError + + @abstractmethod + def __div__(self, other): + """self / other; should promote to float or complex when necessary.""" + raise NotImplementedError + + @abstractmethod + def __rdiv__(self, other): + """other / self""" + raise NotImplementedError + + @abstractmethod + def __pow__(self, exponent): + """self**exponent; should promote to float or complex when necessary.""" + raise NotImplementedError + + @abstractmethod + def __rpow__(self, base): + """base ** self""" + raise NotImplementedError + + @abstractmethod + def __abs__(self): + """Returns the Real distance from 0. Called for abs(self).""" + raise NotImplementedError + + @abstractmethod + def conjugate(self): + """(x+y*i).conjugate() returns (x-y*i).""" + raise NotImplementedError + + @abstractmethod + def __eq__(self, other): + """self == other""" + raise NotImplementedError + + # __ne__ is inherited from object and negates whatever __eq__ does. + +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. + """ + + @abstractmethod + def __float__(self): + """Any Real can be converted to a native float object. + + Called for float(self).""" + raise NotImplementedError + + @abstractmethod + def __trunc__(self): + """trunc(self): Truncates self to an Integral. + + Returns an Integral i such that: + * 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 + def __round__(self, ndigits=None): + """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. + """ + raise NotImplementedError + + def __divmod__(self, other): + """divmod(self, other): The pair (self // other, self % other). + + Sometimes this can be computed faster than the pair of + operations. + """ + return (self // other, self % other) + + def __rdivmod__(self, other): + """divmod(other, self): The pair (self // other, self % other). + + Sometimes this can be computed faster than the pair of + operations. + """ + return (other // self, other % self) + + @abstractmethod + def __floordiv__(self, other): + """self // other: The floor() of self/other.""" + raise NotImplementedError + + @abstractmethod + def __rfloordiv__(self, other): + """other // self: The floor() of other/self.""" + raise NotImplementedError + + @abstractmethod + def __mod__(self, other): + """self % other""" + raise NotImplementedError + + @abstractmethod + def __rmod__(self, other): + """other % self""" + raise NotImplementedError + + @abstractmethod + def __lt__(self, other): + """self < other + + < on Reals defines a total ordering, except perhaps for NaN.""" + raise NotImplementedError + + @abstractmethod + def __le__(self, other): + """self <= other""" + raise NotImplementedError + + # Concrete implementations of Complex abstract methods. + def __complex__(self): + """complex(self) == complex(float(self), 0)""" + return complex(float(self)) + + @property + def real(self): + """Real numbers are their real component.""" + return +self + + @property + def imag(self): + """Real numbers have no imaginary component.""" + return 0 + + def conjugate(self): + """Conjugate is a no-op for Reals.""" + return +self + +Real.register(float) +# Real.register(decimal.Decimal) + + +class Rational(Real, Exact): + """.numerator and .denominator should be in lowest terms.""" + + @abstractproperty + def numerator(self): + raise NotImplementedError + + @abstractproperty + def denominator(self): + raise NotImplementedError + + # Concrete implementation of Real's conversion to float. + def __float__(self): + """float(self) = self.numerator / self.denominator""" + return self.numerator / self.denominator + + +class Integral(Rational): + """Integral adds a conversion to long and the bit-string operations.""" + + @abstractmethod + def __long__(self): + """long(self)""" + raise NotImplementedError + + def __index__(self): + """index(self)""" + return long(self) + + @abstractmethod + def __pow__(self, exponent, modulus=None): + """self ** exponent % modulus, but maybe faster. + + 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. + """ + raise NotImplementedError + + @abstractmethod + def __lshift__(self, other): + """self << other""" + raise NotImplementedError + + @abstractmethod + def __rlshift__(self, other): + """other << self""" + raise NotImplementedError + + @abstractmethod + def __rshift__(self, other): + """self >> other""" + raise NotImplementedError + + @abstractmethod + def __rrshift__(self, other): + """other >> self""" + raise NotImplementedError + + @abstractmethod + def __and__(self, other): + """self & other""" + raise NotImplementedError + + @abstractmethod + def __rand__(self, other): + """other & self""" + raise NotImplementedError + + @abstractmethod + def __xor__(self, other): + """self ^ other""" + raise NotImplementedError + + @abstractmethod + def __rxor__(self, other): + """other ^ self""" + raise NotImplementedError + + @abstractmethod + def __or__(self, other): + """self | other""" + raise NotImplementedError + + @abstractmethod + def __ror__(self, other): + """other | self""" + raise NotImplementedError + + @abstractmethod + def __invert__(self): + """~self""" + raise NotImplementedError + + # Concrete implementations of Rational and Real abstract methods. + def __float__(self): + """float(self) == float(long(self))""" + return float(long(self)) + + @property + def numerator(self): + """Integers are their own numerators.""" + return +self + + @property + def denominator(self): + """Integers have a denominator of 1.""" + return 1 + +Integral.register(int) +Integral.register(long) |