cpython/Lib/numbers.py

432 lines
12 KiB
Python
Raw Normal View History

# 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 __future__ import division
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)
2008-02-11 20:48:20 -04:00
## Notes on Decimal and it how relates to the numeric tower
## --------------------------------------------------------
## Decimal is Real except that it does not support the real and imag properties
## or the conjugate() and complex() methods. If those get defined at some
## point, they cannot use the default implementation which would be sensitive
## to decimal.Context and could produce different answers at different times.
##
## Decimal has some of the characteristics of Integrals. It provides
## logical operations but not as operators. The logical operations only apply
## to a subset of decimals (those that are non-negative, have a zero exponent,
## and have digits that are only 0 or 1). It does provide __long__() and
## a three argument form of __pow__ that includes exactness guarantees.
## It does not provide an __index__() method.
##
## Depending on context, decimal operations may be exact or inexact.
##
## When decimal is run in a context with small precision and automatic rounding,
## it is Inexact. See the "Floating point notes" section of the decimal docs
## for an example of losing the associative and distributive properties of
## addition.
##
## When decimal is used for high precision integer arithmetic, it is Exact.
## When the decimal used as fixed-point, it is Exact.
## When it is run with sufficient precision, it is Exact.
## When the decimal.Inexact trap is set, decimal operations are Exact.
## For an example, see the float_to_decimal() recipe in the "Decimal FAQ"
## section of the docs -- it shows an how traps are used in conjunction
## with variable precision to reliably achieve exact results.
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)."""
# Will be __bool__ in 3.0.
def __nonzero__(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
@abstractmethod
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 without __future__ division
May promote to float.
"""
raise NotImplementedError
@abstractmethod
def __rdiv__(self, other):
"""other / self without __future__ division"""
raise NotImplementedError
@abstractmethod
def __truediv__(self, other):
"""self / other with __future__ division.
Should promote to float when necessary.
"""
raise NotImplementedError
@abstractmethod
def __rtruediv__(self, other):
"""other / self with __future__ division"""
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
def __ne__(self, other):
"""self != other"""
# The default __ne__ doesn't negate __eq__ until 3.0.
return not (self == other)
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
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
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.
"""
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)