mirror of
https://github.com/python/cpython.git
synced 2024-11-24 10:24:35 +08:00
68f5fbe944
svn+ssh://pythondev@svn.python.org/python/trunk ........ r60752 | mark.dickinson | 2008-02-12 22:31:59 +0100 (Tue, 12 Feb 2008) | 5 lines Implementation of Fraction.limit_denominator. Remove Fraction.to_continued_fraction and Fraction.from_continued_fraction ........ r60754 | mark.dickinson | 2008-02-12 22:40:53 +0100 (Tue, 12 Feb 2008) | 3 lines Revert change in r60712: turn alternate constructors back into classmethods instead of staticmethods. ........ r60755 | mark.dickinson | 2008-02-12 22:46:54 +0100 (Tue, 12 Feb 2008) | 4 lines Replace R=fractions.Fraction with F=fractions.Fraction in test_fractions.py. This should have been part of the name change from Rational to Fraction. ........ r60758 | georg.brandl | 2008-02-13 08:20:22 +0100 (Wed, 13 Feb 2008) | 3 lines #2063: correct order of utime and stime in os.times() result on Windows. ........ r60762 | jeffrey.yasskin | 2008-02-13 18:58:04 +0100 (Wed, 13 Feb 2008) | 7 lines Working on issue #1762: Brought ./python.exe -m timeit -s 'from fractions import Fraction; f = Fraction(3, 2)' 'isinstance(3, Fraction); isinstance(f, Fraction)' from 12.3 usec/loop to 3.44 usec/loop and ./python.exe -m timeit -s 'from fractions import Fraction' 'Fraction(3, 2)' from 48.8 usec to 23.6 usec by avoiding genexps and sets in __instancecheck__ and inlining the common case from __subclasscheck__. ........ r60765 | brett.cannon | 2008-02-13 20:15:44 +0100 (Wed, 13 Feb 2008) | 5 lines Fix --enable-universalsdk and its comment line so that zsh's flag completion works. Thanks to Jeroen Ruigrok van der Werven for the fix. ........ r60771 | kurt.kaiser | 2008-02-14 01:08:55 +0100 (Thu, 14 Feb 2008) | 2 lines Bring NEWS.txt up to date from check-in msgs. ........ r60772 | raymond.hettinger | 2008-02-14 02:08:02 +0100 (Thu, 14 Feb 2008) | 3 lines Update notes on Decimal. ........ r60773 | raymond.hettinger | 2008-02-14 03:41:22 +0100 (Thu, 14 Feb 2008) | 1 line Fix decimal repr which should have used single quotes like other reprs. ........ r60785 | jeffrey.yasskin | 2008-02-14 07:12:24 +0100 (Thu, 14 Feb 2008) | 11 lines Performance optimizations on Fraction's constructor. ./python.exe -m timeit -s 'from fractions import Fraction' 'Fraction(3)` 31.7 usec/loop -> 9.2 usec/loop ./python.exe -m timeit -s 'from fractions import Fraction' 'Fraction(3, 2)'` 27.7 usec/loop -> 9.32 usec/loop ./python.exe -m timeit -s 'from fractions import Fraction; f = Fraction(3, 2)' 'Fraction(f)' 31.9 usec/loop -> 14.3 usec/loop ........ r60786 | jeffrey.yasskin | 2008-02-14 08:49:25 +0100 (Thu, 14 Feb 2008) | 5 lines Change simple instances (in Fraction) of self.numerator and self.denominator to self._numerator and self._denominator. This speeds abs() up from 12.2us to 10.8us and trunc() from 2.07us to 1.11us. This doesn't change _add and friends because they're more complicated. ........
428 lines
12 KiB
Python
428 lines
12 KiB
Python
# 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(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).
|
|
"""
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
## 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
|
|
## binary floats.
|
|
##
|
|
## 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)."""
|
|
|
|
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
|
|
|
|
@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 __truediv__(self, other):
|
|
"""self / other: Should promote to float when necessary."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def __rtruediv__(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
|
|
|
|
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
|
|
|
|
@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:"Integral"=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)
|
|
|
|
|
|
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 int and the bit-string operations."""
|
|
|
|
@abstractmethod
|
|
def __int__(self):
|
|
"""int(self)"""
|
|
raise NotImplementedError
|
|
|
|
def __index__(self):
|
|
"""index(self)"""
|
|
return int(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(int(self))"""
|
|
return float(int(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)
|