mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									27edd829d7
								
							
						
					
					
						commit
						2f3c16be73
					
				
					 21 changed files with 1089 additions and 124 deletions
				
			
		|  | @ -986,10 +986,13 @@ available.  They are listed here in alphabetical order. | ||||||
| .. function:: round(x[, n]) | .. function:: round(x[, n]) | ||||||
| 
 | 
 | ||||||
|    Return the floating point value *x* rounded to *n* digits after the decimal |    Return the floating point value *x* rounded to *n* digits after the decimal | ||||||
|    point.  If *n* is omitted, it defaults to zero. The result is a floating point |    point.  If *n* is omitted, it defaults to zero.  Values are rounded to the | ||||||
|    number.  Values are rounded to the closest multiple of 10 to the power minus |    closest multiple of 10 to the power minus *n*; if two multiples are equally | ||||||
|    *n*; if two multiples are equally close, rounding is done away from 0 (so. for |    close, rounding is done toward the even choice (so, for example, both | ||||||
|    example, ``round(0.5)`` is ``1.0`` and ``round(-0.5)`` is ``-1.0``). |    ``round(0.5)`` and ``round(-0.5)`` are ``0``, and ``round(1.5)`` is | ||||||
|  |    ``2``). Delegates to ``x.__round__(n)``. | ||||||
|  | 
 | ||||||
|  |    .. versionchanged:: 2.6 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. function:: set([iterable]) | .. function:: set([iterable]) | ||||||
|  | @ -1132,6 +1135,14 @@ available.  They are listed here in alphabetical order. | ||||||
|    .. versionadded:: 2.2 |    .. versionadded:: 2.2 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | .. function:: trunc(x) | ||||||
|  | 
 | ||||||
|  |    Return the :class:`Real` value *x* truncated to an :class:`Integral` (usually | ||||||
|  |    a long integer). Delegates to ``x.__trunc__()``. | ||||||
|  | 
 | ||||||
|  |    .. versionadded:: 2.6 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| .. function:: tuple([iterable]) | .. function:: tuple([iterable]) | ||||||
| 
 | 
 | ||||||
|    Return a tuple whose items are the same and in the same order as *iterable*'s |    Return a tuple whose items are the same and in the same order as *iterable*'s | ||||||
|  |  | ||||||
|  | @ -26,8 +26,9 @@ Number-theoretic and representation functions: | ||||||
| 
 | 
 | ||||||
| .. function:: ceil(x) | .. function:: ceil(x) | ||||||
| 
 | 
 | ||||||
|    Return the ceiling of *x* as a float, the smallest integer value greater than or |    Return the ceiling of *x* as a float, the smallest integer value greater than | ||||||
|    equal to *x*. |    or equal to *x*. If *x* is not a float, delegates to ``x.__ceil__()``, which | ||||||
|  |    should return an :class:`Integral` value. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. function:: fabs(x) | .. function:: fabs(x) | ||||||
|  | @ -37,8 +38,9 @@ Number-theoretic and representation functions: | ||||||
| 
 | 
 | ||||||
| .. function:: floor(x) | .. function:: floor(x) | ||||||
| 
 | 
 | ||||||
|    Return the floor of *x* as a float, the largest integer value less than or equal |    Return the floor of *x* as a float, the largest integer value less than or | ||||||
|    to *x*. |    equal to *x*. If *x* is not a float, delegates to ``x.__floor__()``, which | ||||||
|  |    should return an :class:`Integral` value. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. function:: fmod(x, y) | .. function:: fmod(x, y) | ||||||
|  |  | ||||||
							
								
								
									
										99
									
								
								Doc/library/numbers.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Doc/library/numbers.rst
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,99 @@ | ||||||
|  | 
 | ||||||
|  | :mod:`numbers` --- Numeric abstract base classes | ||||||
|  | ================================================ | ||||||
|  | 
 | ||||||
|  | .. module:: numbers | ||||||
|  |    :synopsis: Numeric abstract base classes (Complex, Real, Integral, etc.). | ||||||
|  | 
 | ||||||
|  | The :mod:`numbers` module (:pep:`3141`) defines a hierarchy of numeric abstract | ||||||
|  | base classes which progressively define more operations. These concepts also | ||||||
|  | provide a way to distinguish exact from inexact types. None of the types defined | ||||||
|  | in this module can be instantiated. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. class:: Number | ||||||
|  | 
 | ||||||
|  |    The root of the numeric hierarchy. If you just want to check if an argument | ||||||
|  |    *x* is a number, without caring what kind, use ``isinstance(x, Number)``. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Exact and inexact operations | ||||||
|  | ---------------------------- | ||||||
|  | 
 | ||||||
|  | .. class:: Exact | ||||||
|  | 
 | ||||||
|  |    Subclasses of this type have exact operations. | ||||||
|  | 
 | ||||||
|  |    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. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. class:: Inexact | ||||||
|  | 
 | ||||||
|  |    Subclasses of this type have inexact operations. | ||||||
|  | 
 | ||||||
|  |    Given X, an instance of :class:`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. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | The numeric tower | ||||||
|  | ----------------- | ||||||
|  | 
 | ||||||
|  | .. class:: Complex | ||||||
|  | 
 | ||||||
|  |    Subclasses of this type describe complex numbers and include the operations | ||||||
|  |    that work on the builtin :class:`complex` type. These are: conversions to | ||||||
|  |    :class:`complex` and :class:`bool`, :attr:`.real`, :attr:`.imag`, ``+``, | ||||||
|  |    ``-``, ``*``, ``/``, :func:`abs`, :meth:`conjugate`, ``==``, and ``!=``. All | ||||||
|  |    except ``-`` and ``!=`` are abstract. | ||||||
|  | 
 | ||||||
|  | .. attribute:: Complex.real | ||||||
|  | 
 | ||||||
|  |    Abstract. Retrieves the :class:`Real` component of this number. | ||||||
|  | 
 | ||||||
|  | .. attribute:: Complex.imag | ||||||
|  | 
 | ||||||
|  |    Abstract. Retrieves the :class:`Real` component of this number. | ||||||
|  | 
 | ||||||
|  | .. method:: Complex.conjugate() | ||||||
|  | 
 | ||||||
|  |    Abstract. Returns the complex conjugate. For example, ``(1+3j).conjugate() == | ||||||
|  |    (1-3j)``. | ||||||
|  | 
 | ||||||
|  | .. class:: Real | ||||||
|  | 
 | ||||||
|  |    To :class:`Complex`, :class:`Real` adds the operations that work on real | ||||||
|  |    numbers. | ||||||
|  | 
 | ||||||
|  |    In short, those are: a conversion to :class:`float`, :func:`trunc`, | ||||||
|  |    :func:`round`, :func:`math.floor`, :func:`math.ceil`, :func:`divmod`, ``//``, | ||||||
|  |    ``%``, ``<``, ``<=``, ``>``, and ``>=``. | ||||||
|  | 
 | ||||||
|  |    Real also provides defaults for :func:`complex`, :attr:`Complex.real`, | ||||||
|  |    :attr:`Complex.imag`, and :meth:`Complex.conjugate`. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. class:: Rational | ||||||
|  | 
 | ||||||
|  |    Subtypes both :class:`Real` and :class:`Exact`, and adds | ||||||
|  |    :attr:`Rational.numerator` and :attr:`Rational.denominator` properties, which | ||||||
|  |    should be in lowest terms. With these, it provides a default for | ||||||
|  |    :func:`float`. | ||||||
|  | 
 | ||||||
|  | .. attribute:: Rational.numerator | ||||||
|  | 
 | ||||||
|  |    Abstract. | ||||||
|  | 
 | ||||||
|  | .. attribute:: Rational.denominator | ||||||
|  | 
 | ||||||
|  |    Abstract. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. class:: Integral | ||||||
|  | 
 | ||||||
|  |    Subtypes :class:`Rational` and adds a conversion to :class:`long`, the | ||||||
|  |    3-argument form of :func:`pow`, and the bit-string operations: ``<<``, | ||||||
|  |    ``>>``, ``&``, ``^``, ``|``, ``~``. Provides defaults for :func:`float`, | ||||||
|  |    :attr:`Rational.numerator`, and :attr:`Rational.denominator`. | ||||||
|  | @ -6,16 +6,18 @@ Numeric and Mathematical Modules | ||||||
| ******************************** | ******************************** | ||||||
| 
 | 
 | ||||||
| The modules described in this chapter provide numeric and math-related functions | The modules described in this chapter provide numeric and math-related functions | ||||||
| and data types. The :mod:`math` and :mod:`cmath` contain  various mathematical | and data types. The :mod:`numbers` module defines an abstract hierarchy of | ||||||
| functions for floating-point and complex numbers. For users more interested in | numeric types. The :mod:`math` and :mod:`cmath` modules contain various | ||||||
| decimal accuracy than in speed, the  :mod:`decimal` module supports exact | mathematical functions for floating-point and complex numbers. For users more | ||||||
| representations of  decimal numbers. | interested in decimal accuracy than in speed, the :mod:`decimal` module supports | ||||||
|  | exact representations of decimal numbers. | ||||||
| 
 | 
 | ||||||
| The following modules are documented in this chapter: | The following modules are documented in this chapter: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. toctree:: | .. toctree:: | ||||||
| 
 | 
 | ||||||
|  |    numbers.rst | ||||||
|    math.rst |    math.rst | ||||||
|    cmath.rst |    cmath.rst | ||||||
|    decimal.rst |    decimal.rst | ||||||
|  |  | ||||||
|  | @ -270,9 +270,8 @@ numbers of mixed type use the same rule. [#]_ The constructors :func:`int`, | ||||||
| :func:`long`, :func:`float`, and :func:`complex` can be used to produce numbers | :func:`long`, :func:`float`, and :func:`complex` can be used to produce numbers | ||||||
| of a specific type. | of a specific type. | ||||||
| 
 | 
 | ||||||
| All numeric types (except complex) support the following operations, sorted by | All builtin numeric types support the following operations. See | ||||||
| ascending priority (operations in the same box have the same priority; all | :ref:`power` and later sections for the operators' priorities. | ||||||
| numeric operations have a higher priority than comparison operations): |  | ||||||
| 
 | 
 | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | Operation          | Result                          | Notes  | | | Operation          | Result                          | Notes  | | ||||||
|  | @ -285,7 +284,7 @@ numeric operations have a higher priority than comparison operations): | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``x / y``          | quotient of *x* and *y*         | \(1)   | | | ``x / y``          | quotient of *x* and *y*         | \(1)   | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``x // y``         | (floored) quotient of *x* and   | \(5)   | | | ``x // y``         | (floored) quotient of *x* and   | (4)(5) | | ||||||
| |                    | *y*                             |        | | |                    | *y*                             |        | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``x % y``          | remainder of ``x / y``          | \(4)   | | | ``x % y``          | remainder of ``x / y``          | \(4)   | | ||||||
|  | @ -294,7 +293,7 @@ numeric operations have a higher priority than comparison operations): | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``+x``             | *x* unchanged                   |        | | | ``+x``             | *x* unchanged                   |        | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``abs(x)``         | absolute value or magnitude of  |        | | | ``abs(x)``         | absolute value or magnitude of  | \(3)   | | ||||||
| |                    | *x*                             |        | | |                    | *x*                             |        | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``int(x)``         | *x* converted to integer        | \(2)   | | | ``int(x)``         | *x* converted to integer        | \(2)   | | ||||||
|  | @ -308,11 +307,11 @@ numeric operations have a higher priority than comparison operations): | ||||||
| |                    | *im* defaults to zero.          |        | | |                    | *im* defaults to zero.          |        | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``c.conjugate()``  | conjugate of the complex number |        | | | ``c.conjugate()``  | conjugate of the complex number |        | | ||||||
| |                    | *c*                             |        | | |                    | *c*. (Identity on real numbers) |        | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``divmod(x, y)``   | the pair ``(x // y, x % y)``    | (3)(4) | | | ``divmod(x, y)``   | the pair ``(x // y, x % y)``    | (3)(4) | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``pow(x, y)``      | *x* to the power *y*            |        | | | ``pow(x, y)``      | *x* to the power *y*            | \(3)   | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
| | ``x ** y``         | *x* to the power *y*            |        | | | ``x ** y``         | *x* to the power *y*            |        | | ||||||
| +--------------------+---------------------------------+--------+ | +--------------------+---------------------------------+--------+ | ||||||
|  | @ -341,9 +340,12 @@ Notes: | ||||||
|       pair: numeric; conversions |       pair: numeric; conversions | ||||||
|       pair: C; language |       pair: C; language | ||||||
| 
 | 
 | ||||||
|    Conversion from floating point to (long or plain) integer may round or truncate |    Conversion from floating point to (long or plain) integer may round or | ||||||
|    as in C; see functions :func:`floor` and :func:`ceil` in the :mod:`math` module |    truncate as in C. | ||||||
|    for well-defined conversions. | 
 | ||||||
|  |    .. deprecated:: 2.6 | ||||||
|  |       Instead, convert floats to long explicitly with :func:`trunc`, | ||||||
|  |       :func:`math.floor`, or :func:`math.ceil`. | ||||||
| 
 | 
 | ||||||
| (3) | (3) | ||||||
|    See :ref:`built-in-funcs` for a full description. |    See :ref:`built-in-funcs` for a full description. | ||||||
|  | @ -364,6 +366,22 @@ Notes: | ||||||
|     |     | ||||||
|    .. versionadded:: 2.6 |    .. versionadded:: 2.6 | ||||||
| 
 | 
 | ||||||
|  | All :class:`numbers.Real` types (:class:`int`, :class:`long`, and | ||||||
|  | :class:`float`) also include the following operations: | ||||||
|  | 
 | ||||||
|  | +--------------------+--------------------------------+--------+ | ||||||
|  | | Operation          | Result                         | Notes  | | ||||||
|  | +====================+================================+========+ | ||||||
|  | | ``trunc(x)``       | *x* truncated to Integral      |        | | ||||||
|  | +--------------------+--------------------------------+--------+ | ||||||
|  | | ``round(x[, n])``  | *x* rounded to n digits,       |        | | ||||||
|  | |                    | rounding half to even. If n is |        | | ||||||
|  | |                    | omitted, it defaults to 0.     |        | | ||||||
|  | +--------------------+--------------------------------+--------+ | ||||||
|  | | ``math.floor(x)``  | the greatest Integral <= *x*   |        | | ||||||
|  | +--------------------+--------------------------------+--------+ | ||||||
|  | | ``math.ceil(x)``   | the least Integral >= *x*      |        | | ||||||
|  | +--------------------+--------------------------------+--------+ | ||||||
| 
 | 
 | ||||||
| .. XXXJH exceptions: overflow (when? what operations?) zerodivision | .. XXXJH exceptions: overflow (when? what operations?) zerodivision | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -150,7 +150,7 @@ Ellipsis | ||||||
|    indicate the presence of the ``...`` syntax in a slice.  Its truth value is |    indicate the presence of the ``...`` syntax in a slice.  Its truth value is | ||||||
|    true. |    true. | ||||||
| 
 | 
 | ||||||
| Numbers | :class:`numbers.Number` | ||||||
|    .. index:: object: numeric |    .. index:: object: numeric | ||||||
| 
 | 
 | ||||||
|    These are created by numeric literals and returned as results by arithmetic |    These are created by numeric literals and returned as results by arithmetic | ||||||
|  | @ -162,7 +162,7 @@ Numbers | ||||||
|    Python distinguishes between integers, floating point numbers, and complex |    Python distinguishes between integers, floating point numbers, and complex | ||||||
|    numbers: |    numbers: | ||||||
| 
 | 
 | ||||||
|    Integers |    :class:`numbers.Integral` | ||||||
|       .. index:: object: integer |       .. index:: object: integer | ||||||
| 
 | 
 | ||||||
|       These represent elements from the mathematical set of integers (positive and |       These represent elements from the mathematical set of integers (positive and | ||||||
|  | @ -214,7 +214,7 @@ Numbers | ||||||
|       without causing overflow, will yield the same result in the long integer domain |       without causing overflow, will yield the same result in the long integer domain | ||||||
|       or when using mixed operands. |       or when using mixed operands. | ||||||
| 
 | 
 | ||||||
|    Floating point numbers |    :class:`numbers.Real` (:class:`float`) | ||||||
|       .. index:: |       .. index:: | ||||||
|          object: floating point |          object: floating point | ||||||
|          pair: floating point; number |          pair: floating point; number | ||||||
|  | @ -229,7 +229,7 @@ Numbers | ||||||
|       overhead of using objects in Python, so there is no reason to complicate the |       overhead of using objects in Python, so there is no reason to complicate the | ||||||
|       language with two kinds of floating point numbers. |       language with two kinds of floating point numbers. | ||||||
| 
 | 
 | ||||||
|    Complex numbers |    :class:`numbers.Complex` | ||||||
|       .. index:: |       .. index:: | ||||||
|          object: complex |          object: complex | ||||||
|          pair: complex; number |          pair: complex; number | ||||||
|  |  | ||||||
|  | @ -801,7 +801,8 @@ were of integer types and the second argument was negative, an exception was | ||||||
| raised). | raised). | ||||||
| 
 | 
 | ||||||
| Raising ``0.0`` to a negative power results in a :exc:`ZeroDivisionError`. | Raising ``0.0`` to a negative power results in a :exc:`ZeroDivisionError`. | ||||||
| Raising a negative number to a fractional power results in a :exc:`ValueError`. | Raising a negative number to a fractional power results in a :class:`complex` | ||||||
|  | number. (Since Python 2.6. In earlier versions it raised a :exc:`ValueError`.) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. _unary: | .. _unary: | ||||||
|  |  | ||||||
							
								
								
									
										393
									
								
								Lib/numbers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								Lib/numbers.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -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) | ||||||
							
								
								
									
										62
									
								
								Lib/test/test_abstract_numbers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								Lib/test/test_abstract_numbers.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | ||||||
|  | """Unit tests for numbers.py.""" | ||||||
|  | 
 | ||||||
|  | import unittest | ||||||
|  | from test import test_support | ||||||
|  | from numbers import Number | ||||||
|  | from numbers import Exact, Inexact | ||||||
|  | from numbers import Complex, Real, Rational, Integral | ||||||
|  | import operator | ||||||
|  | 
 | ||||||
|  | class TestNumbers(unittest.TestCase): | ||||||
|  |     def test_int(self): | ||||||
|  |         self.failUnless(issubclass(int, Integral)) | ||||||
|  |         self.failUnless(issubclass(int, Complex)) | ||||||
|  |         self.failUnless(issubclass(int, Exact)) | ||||||
|  |         self.failIf(issubclass(int, Inexact)) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(7, int(7).real) | ||||||
|  |         self.assertEqual(0, int(7).imag) | ||||||
|  |         self.assertEqual(7, int(7).conjugate()) | ||||||
|  |         self.assertEqual(7, int(7).numerator) | ||||||
|  |         self.assertEqual(1, int(7).denominator) | ||||||
|  | 
 | ||||||
|  |     def test_long(self): | ||||||
|  |         self.failUnless(issubclass(long, Integral)) | ||||||
|  |         self.failUnless(issubclass(long, Complex)) | ||||||
|  |         self.failUnless(issubclass(long, Exact)) | ||||||
|  |         self.failIf(issubclass(long, Inexact)) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(7, long(7).real) | ||||||
|  |         self.assertEqual(0, long(7).imag) | ||||||
|  |         self.assertEqual(7, long(7).conjugate()) | ||||||
|  |         self.assertEqual(7, long(7).numerator) | ||||||
|  |         self.assertEqual(1, long(7).denominator) | ||||||
|  | 
 | ||||||
|  |     def test_float(self): | ||||||
|  |         self.failIf(issubclass(float, Rational)) | ||||||
|  |         self.failUnless(issubclass(float, Real)) | ||||||
|  |         self.failIf(issubclass(float, Exact)) | ||||||
|  |         self.failUnless(issubclass(float, Inexact)) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(7.3, float(7.3).real) | ||||||
|  |         self.assertEqual(0, float(7.3).imag) | ||||||
|  |         self.assertEqual(7.3, float(7.3).conjugate()) | ||||||
|  | 
 | ||||||
|  |     def test_complex(self): | ||||||
|  |         self.failIf(issubclass(complex, Real)) | ||||||
|  |         self.failUnless(issubclass(complex, Complex)) | ||||||
|  |         self.failIf(issubclass(complex, Exact)) | ||||||
|  |         self.failUnless(issubclass(complex, Inexact)) | ||||||
|  | 
 | ||||||
|  |         c1, c2 = complex(3, 2), complex(4,1) | ||||||
|  |         # XXX: This is not ideal, but see the comment in builtin_trunc(). | ||||||
|  |         self.assertRaises(AttributeError, trunc, c1) | ||||||
|  |         self.assertRaises(TypeError, float, c1) | ||||||
|  |         self.assertRaises(TypeError, int, c1) | ||||||
|  | 
 | ||||||
|  | def test_main(): | ||||||
|  |     test_support.run_unittest(TestNumbers) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     unittest.main() | ||||||
|  | @ -1450,11 +1450,13 @@ def test_pow(self): | ||||||
|                     else: |                     else: | ||||||
|                         self.assertAlmostEqual(pow(x, y, z), 24.0) |                         self.assertAlmostEqual(pow(x, y, z), 24.0) | ||||||
| 
 | 
 | ||||||
|  |         self.assertAlmostEqual(pow(-1, 0.5), 1j) | ||||||
|  |         self.assertAlmostEqual(pow(-1, 1./3), 0.5 + 0.8660254037844386j) | ||||||
|  | 
 | ||||||
|         self.assertRaises(TypeError, pow, -1, -2, 3) |         self.assertRaises(TypeError, pow, -1, -2, 3) | ||||||
|         self.assertRaises(ValueError, pow, 1, 2, 0) |         self.assertRaises(ValueError, pow, 1, 2, 0) | ||||||
|         self.assertRaises(TypeError, pow, -1L, -2L, 3L) |         self.assertRaises(TypeError, pow, -1L, -2L, 3L) | ||||||
|         self.assertRaises(ValueError, pow, 1L, 2L, 0L) |         self.assertRaises(ValueError, pow, 1L, 2L, 0L) | ||||||
|         self.assertRaises(ValueError, pow, -342.43, 0.234) |  | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(TypeError, pow) |         self.assertRaises(TypeError, pow) | ||||||
| 
 | 
 | ||||||
|  | @ -1622,6 +1624,7 @@ def test_repr(self): | ||||||
| 
 | 
 | ||||||
|     def test_round(self): |     def test_round(self): | ||||||
|         self.assertEqual(round(0.0), 0.0) |         self.assertEqual(round(0.0), 0.0) | ||||||
|  |         self.assertEqual(type(round(0.0)), float)  # Will be int in 3.0. | ||||||
|         self.assertEqual(round(1.0), 1.0) |         self.assertEqual(round(1.0), 1.0) | ||||||
|         self.assertEqual(round(10.0), 10.0) |         self.assertEqual(round(10.0), 10.0) | ||||||
|         self.assertEqual(round(1000000000.0), 1000000000.0) |         self.assertEqual(round(1000000000.0), 1000000000.0) | ||||||
|  | @ -1650,12 +1653,50 @@ def test_round(self): | ||||||
|         self.assertEqual(round(-999999999.9), -1000000000.0) |         self.assertEqual(round(-999999999.9), -1000000000.0) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(round(-8.0, -1), -10.0) |         self.assertEqual(round(-8.0, -1), -10.0) | ||||||
|  |         self.assertEqual(type(round(-8.0, -1)), float) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(type(round(-8.0, 0)), float) | ||||||
|  |         self.assertEqual(type(round(-8.0, 1)), float) | ||||||
|  | 
 | ||||||
|  |         # Check even / odd rounding behaviour | ||||||
|  |         self.assertEqual(round(5.5), 6) | ||||||
|  |         self.assertEqual(round(6.5), 6) | ||||||
|  |         self.assertEqual(round(-5.5), -6) | ||||||
|  |         self.assertEqual(round(-6.5), -6) | ||||||
|  | 
 | ||||||
|  |         # Check behavior on ints | ||||||
|  |         self.assertEqual(round(0), 0) | ||||||
|  |         self.assertEqual(round(8), 8) | ||||||
|  |         self.assertEqual(round(-8), -8) | ||||||
|  |         self.assertEqual(type(round(0)), float)  # Will be int in 3.0. | ||||||
|  |         self.assertEqual(type(round(-8, -1)), float) | ||||||
|  |         self.assertEqual(type(round(-8, 0)), float) | ||||||
|  |         self.assertEqual(type(round(-8, 1)), float) | ||||||
| 
 | 
 | ||||||
|         # test new kwargs |         # test new kwargs | ||||||
|         self.assertEqual(round(number=-8.0, ndigits=-1), -10.0) |         self.assertEqual(round(number=-8.0, ndigits=-1), -10.0) | ||||||
| 
 | 
 | ||||||
|         self.assertRaises(TypeError, round) |         self.assertRaises(TypeError, round) | ||||||
| 
 | 
 | ||||||
|  |         # test generic rounding delegation for reals | ||||||
|  |         class TestRound(object): | ||||||
|  |             def __round__(self): | ||||||
|  |                 return 23 | ||||||
|  | 
 | ||||||
|  |         class TestNoRound(object): | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(round(TestRound()), 23) | ||||||
|  | 
 | ||||||
|  |         self.assertRaises(TypeError, round, 1, 2, 3) | ||||||
|  |         # XXX: This is not ideal, but see the comment in builtin_round(). | ||||||
|  |         self.assertRaises(AttributeError, round, TestNoRound()) | ||||||
|  | 
 | ||||||
|  |         t = TestNoRound() | ||||||
|  |         t.__round__ = lambda *args: args | ||||||
|  |         self.assertEquals((), round(t)) | ||||||
|  |         self.assertEquals((0,), round(t, 0)) | ||||||
|  | 
 | ||||||
|     def test_setattr(self): |     def test_setattr(self): | ||||||
|         setattr(sys, 'spam', 1) |         setattr(sys, 'spam', 1) | ||||||
|         self.assertEqual(sys.spam, 1) |         self.assertEqual(sys.spam, 1) | ||||||
|  | @ -1697,6 +1738,38 @@ def __getitem__(self, index): | ||||||
|                 raise ValueError |                 raise ValueError | ||||||
|         self.assertRaises(ValueError, sum, BadSeq()) |         self.assertRaises(ValueError, sum, BadSeq()) | ||||||
| 
 | 
 | ||||||
|  |     def test_trunc(self): | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(trunc(1), 1) | ||||||
|  |         self.assertEqual(trunc(-1), -1) | ||||||
|  |         self.assertEqual(type(trunc(1)), int) | ||||||
|  |         self.assertEqual(type(trunc(1.5)), int) | ||||||
|  |         self.assertEqual(trunc(1.5), 1) | ||||||
|  |         self.assertEqual(trunc(-1.5), -1) | ||||||
|  |         self.assertEqual(trunc(1.999999), 1) | ||||||
|  |         self.assertEqual(trunc(-1.999999), -1) | ||||||
|  |         self.assertEqual(trunc(-0.999999), -0) | ||||||
|  |         self.assertEqual(trunc(-100.999), -100) | ||||||
|  | 
 | ||||||
|  |         class TestTrunc(object): | ||||||
|  |             def __trunc__(self): | ||||||
|  |                 return 23 | ||||||
|  | 
 | ||||||
|  |         class TestNoTrunc(object): | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(trunc(TestTrunc()), 23) | ||||||
|  | 
 | ||||||
|  |         self.assertRaises(TypeError, trunc) | ||||||
|  |         self.assertRaises(TypeError, trunc, 1, 2) | ||||||
|  |         # XXX: This is not ideal, but see the comment in builtin_trunc(). | ||||||
|  |         self.assertRaises(AttributeError, trunc, TestNoTrunc()) | ||||||
|  | 
 | ||||||
|  |         t = TestNoTrunc() | ||||||
|  |         t.__trunc__ = lambda *args: args | ||||||
|  |         self.assertEquals((), trunc(t)) | ||||||
|  |         self.assertRaises(TypeError, trunc, t, 0) | ||||||
|  | 
 | ||||||
|     def test_tuple(self): |     def test_tuple(self): | ||||||
|         self.assertEqual(tuple(()), ()) |         self.assertEqual(tuple(()), ()) | ||||||
|         t0_3 = (0, 1, 2, 3) |         t0_3 = (0, 1, 2, 3) | ||||||
|  |  | ||||||
|  | @ -385,7 +385,9 @@ def test_float_overflow(self): | ||||||
|                      "1. ** huge", "huge ** 1.", "1. ** mhuge", "mhuge ** 1.", |                      "1. ** huge", "huge ** 1.", "1. ** mhuge", "mhuge ** 1.", | ||||||
|                      "math.sin(huge)", "math.sin(mhuge)", |                      "math.sin(huge)", "math.sin(mhuge)", | ||||||
|                      "math.sqrt(huge)", "math.sqrt(mhuge)", # should do better |                      "math.sqrt(huge)", "math.sqrt(mhuge)", # should do better | ||||||
|                      "math.floor(huge)", "math.floor(mhuge)"]: |                      # math.floor() of an int returns an int now | ||||||
|  |                      ##"math.floor(huge)", "math.floor(mhuge)", | ||||||
|  |                      ]: | ||||||
| 
 | 
 | ||||||
|             self.assertRaises(OverflowError, eval, test, namespace) |             self.assertRaises(OverflowError, eval, test, namespace) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -58,6 +58,19 @@ def testCeil(self): | ||||||
|         self.ftest('ceil(-1.0)', math.ceil(-1.0), -1) |         self.ftest('ceil(-1.0)', math.ceil(-1.0), -1) | ||||||
|         self.ftest('ceil(-1.5)', math.ceil(-1.5), -1) |         self.ftest('ceil(-1.5)', math.ceil(-1.5), -1) | ||||||
| 
 | 
 | ||||||
|  |         class TestCeil(object): | ||||||
|  |             def __ceil__(self): | ||||||
|  |                 return 42 | ||||||
|  |         class TestNoCeil(object): | ||||||
|  |             pass | ||||||
|  |         self.ftest('ceil(TestCeil())', math.ceil(TestCeil()), 42) | ||||||
|  |         self.assertRaises(TypeError, math.ceil, TestNoCeil()) | ||||||
|  | 
 | ||||||
|  |         t = TestNoCeil() | ||||||
|  |         t.__ceil__ = lambda *args: args | ||||||
|  |         self.assertRaises(TypeError, math.ceil, t) | ||||||
|  |         self.assertRaises(TypeError, math.ceil, t, 0) | ||||||
|  | 
 | ||||||
|     def testCos(self): |     def testCos(self): | ||||||
|         self.assertRaises(TypeError, math.cos) |         self.assertRaises(TypeError, math.cos) | ||||||
|         self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0) |         self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0) | ||||||
|  | @ -101,6 +114,19 @@ def testFloor(self): | ||||||
|         self.ftest('floor(1.23e167)', math.floor(1.23e167), 1.23e167) |         self.ftest('floor(1.23e167)', math.floor(1.23e167), 1.23e167) | ||||||
|         self.ftest('floor(-1.23e167)', math.floor(-1.23e167), -1.23e167) |         self.ftest('floor(-1.23e167)', math.floor(-1.23e167), -1.23e167) | ||||||
| 
 | 
 | ||||||
|  |         class TestFloor(object): | ||||||
|  |             def __floor__(self): | ||||||
|  |                 return 42 | ||||||
|  |         class TestNoFloor(object): | ||||||
|  |             pass | ||||||
|  |         self.ftest('floor(TestFloor())', math.floor(TestFloor()), 42) | ||||||
|  |         self.assertRaises(TypeError, math.floor, TestNoFloor()) | ||||||
|  | 
 | ||||||
|  |         t = TestNoFloor() | ||||||
|  |         t.__floor__ = lambda *args: args | ||||||
|  |         self.assertRaises(TypeError, math.floor, t) | ||||||
|  |         self.assertRaises(TypeError, math.floor, t, 0) | ||||||
|  | 
 | ||||||
|     def testFmod(self): |     def testFmod(self): | ||||||
|         self.assertRaises(TypeError, math.fmod) |         self.assertRaises(TypeError, math.fmod) | ||||||
|         self.ftest('fmod(10,1)', math.fmod(10,1), 0) |         self.ftest('fmod(10,1)', math.fmod(10,1), 0) | ||||||
|  |  | ||||||
|  | @ -2264,13 +2264,34 @@ def defaultTestResult(self): | ||||||
|         expected = ['startTest', 'test', 'stopTest'] |         expected = ['startTest', 'test', 'stopTest'] | ||||||
|         self.assertEqual(events, expected) |         self.assertEqual(events, expected) | ||||||
| 
 | 
 | ||||||
|  | class Test_Assertions(TestCase): | ||||||
|  |     def test_AlmostEqual(self): | ||||||
|  |         self.failUnlessAlmostEqual(1.00000001, 1.0) | ||||||
|  |         self.failIfAlmostEqual(1.0000001, 1.0) | ||||||
|  |         self.assertRaises(AssertionError, | ||||||
|  |                           self.failUnlessAlmostEqual, 1.0000001, 1.0) | ||||||
|  |         self.assertRaises(AssertionError, | ||||||
|  |                           self.failIfAlmostEqual, 1.00000001, 1.0) | ||||||
|  | 
 | ||||||
|  |         self.failUnlessAlmostEqual(1.1, 1.0, places=0) | ||||||
|  |         self.assertRaises(AssertionError, | ||||||
|  |                           self.failUnlessAlmostEqual, 1.1, 1.0, places=1) | ||||||
|  | 
 | ||||||
|  |         self.failUnlessAlmostEqual(0, .1+.1j, places=0) | ||||||
|  |         self.failIfAlmostEqual(0, .1+.1j, places=1) | ||||||
|  |         self.assertRaises(AssertionError, | ||||||
|  |                           self.failUnlessAlmostEqual, 0, .1+.1j, places=1) | ||||||
|  |         self.assertRaises(AssertionError, | ||||||
|  |                           self.failIfAlmostEqual, 0, .1+.1j, places=0) | ||||||
|  | 
 | ||||||
| ###################################################################### | ###################################################################### | ||||||
| ## Main | ## Main | ||||||
| ###################################################################### | ###################################################################### | ||||||
| 
 | 
 | ||||||
| def test_main(): | def test_main(): | ||||||
|     test_support.run_unittest(Test_TestCase, Test_TestLoader, |     test_support.run_unittest(Test_TestCase, Test_TestLoader, | ||||||
|         Test_TestSuite, Test_TestResult, Test_FunctionTestCase) |         Test_TestSuite, Test_TestResult, Test_FunctionTestCase, | ||||||
|  |         Test_Assertions) | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     test_main() |     test_main() | ||||||
|  |  | ||||||
|  | @ -358,7 +358,7 @@ def failUnlessAlmostEqual(self, first, second, places=7, msg=None): | ||||||
|            Note that decimal places (from zero) are usually not the same |            Note that decimal places (from zero) are usually not the same | ||||||
|            as significant digits (measured from the most signficant digit). |            as significant digits (measured from the most signficant digit). | ||||||
|         """ |         """ | ||||||
|         if round(second-first, places) != 0: |         if round(abs(second-first), places) != 0: | ||||||
|             raise self.failureException, \ |             raise self.failureException, \ | ||||||
|                   (msg or '%r != %r within %r places' % (first, second, places)) |                   (msg or '%r != %r within %r places' % (first, second, places)) | ||||||
| 
 | 
 | ||||||
|  | @ -370,7 +370,7 @@ def failIfAlmostEqual(self, first, second, places=7, msg=None): | ||||||
|            Note that decimal places (from zero) are usually not the same |            Note that decimal places (from zero) are usually not the same | ||||||
|            as significant digits (measured from the most signficant digit). |            as significant digits (measured from the most signficant digit). | ||||||
|         """ |         """ | ||||||
|         if round(second-first, places) == 0: |         if round(abs(second-first), places) == 0: | ||||||
|             raise self.failureException, \ |             raise self.failureException, \ | ||||||
|                   (msg or '%r == %r within %r places' % (first, second, places)) |                   (msg or '%r == %r within %r places' % (first, second, places)) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -346,6 +346,8 @@ Core and builtins | ||||||
| Library | Library | ||||||
| ------- | ------- | ||||||
| 
 | 
 | ||||||
|  | - Issue #1689: PEP 3141, numeric abstract base classes. | ||||||
|  | 
 | ||||||
| - Tk issue #1851526: Return results from Python callbacks to Tcl as | - Tk issue #1851526: Return results from Python callbacks to Tcl as | ||||||
|   Tcl objects. |   Tcl objects. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -107,9 +107,28 @@ FUNC1(atan, atan, | ||||||
| FUNC2(atan2, atan2, | FUNC2(atan2, atan2, | ||||||
|       "atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n" |       "atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n" | ||||||
|       "Unlike atan(y/x), the signs of both x and y are considered.") |       "Unlike atan(y/x), the signs of both x and y are considered.") | ||||||
| FUNC1(ceil, ceil, | 
 | ||||||
|  | static PyObject * math_ceil(PyObject *self, PyObject *number) { | ||||||
|  | 	static PyObject *ceil_str = NULL; | ||||||
|  | 	PyObject *method; | ||||||
|  | 
 | ||||||
|  | 	if (ceil_str == NULL) { | ||||||
|  | 		ceil_str = PyString_FromString("__ceil__"); | ||||||
|  | 		if (ceil_str == NULL) | ||||||
|  | 			return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	method = _PyType_Lookup(Py_Type(number), ceil_str); | ||||||
|  | 	if (method == NULL) | ||||||
|  | 		return math_1(number, ceil); | ||||||
|  | 	else | ||||||
|  | 		return PyObject_CallFunction(method, "O", number); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(math_ceil_doc, | ||||||
| 	     "ceil(x)\n\nReturn the ceiling of x as a float.\n" | 	     "ceil(x)\n\nReturn the ceiling of x as a float.\n" | ||||||
|       "This is the smallest integral value >= x.") | 	     "This is the smallest integral value >= x."); | ||||||
|  | 
 | ||||||
| FUNC1(cos, cos, | FUNC1(cos, cos, | ||||||
|       "cos(x)\n\nReturn the cosine of x (measured in radians).") |       "cos(x)\n\nReturn the cosine of x (measured in radians).") | ||||||
| FUNC1(cosh, cosh, | FUNC1(cosh, cosh, | ||||||
|  | @ -118,9 +137,28 @@ FUNC1(exp, exp, | ||||||
|       "exp(x)\n\nReturn e raised to the power of x.") |       "exp(x)\n\nReturn e raised to the power of x.") | ||||||
| FUNC1(fabs, fabs, | FUNC1(fabs, fabs, | ||||||
|       "fabs(x)\n\nReturn the absolute value of the float x.") |       "fabs(x)\n\nReturn the absolute value of the float x.") | ||||||
| FUNC1(floor, floor, | 
 | ||||||
|  | static PyObject * math_floor(PyObject *self, PyObject *number) { | ||||||
|  | 	static PyObject *floor_str = NULL; | ||||||
|  | 	PyObject *method; | ||||||
|  | 
 | ||||||
|  | 	if (floor_str == NULL) { | ||||||
|  | 		floor_str = PyString_FromString("__floor__"); | ||||||
|  | 		if (floor_str == NULL) | ||||||
|  | 			return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	method = _PyType_Lookup(Py_Type(number), floor_str); | ||||||
|  | 	if (method == NULL) | ||||||
|  | 		return math_1(number, floor); | ||||||
|  | 	else | ||||||
|  | 		return PyObject_CallFunction(method, "O", number); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(math_floor_doc, | ||||||
| 	     "floor(x)\n\nReturn the floor of x as a float.\n" | 	     "floor(x)\n\nReturn the floor of x as a float.\n" | ||||||
|       "This is the largest integral value <= x.") | 	     "This is the largest integral value <= x."); | ||||||
|  | 
 | ||||||
| FUNC2(fmod, fmod, | FUNC2(fmod, fmod, | ||||||
|       "fmod(x,y)\n\nReturn fmod(x, y), according to platform C." |       "fmod(x,y)\n\nReturn fmod(x, y), according to platform C." | ||||||
|       "  x % y may differ.") |       "  x % y may differ.") | ||||||
|  |  | ||||||
|  | @ -385,6 +385,41 @@ complex_hash(PyComplexObject *v) | ||||||
| 	return combined; | 	return combined; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* This macro may return! */ | ||||||
|  | #define TO_COMPLEX(obj, c) \ | ||||||
|  | 	if (PyComplex_Check(obj)) \ | ||||||
|  | 		c = ((PyComplexObject *)(obj))->cval; \ | ||||||
|  | 	else if (to_complex(&(obj), &(c)) < 0) \ | ||||||
|  | 		return (obj) | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | to_complex(PyObject **pobj, Py_complex *pc) | ||||||
|  | { | ||||||
|  |     PyObject *obj = *pobj; | ||||||
|  | 
 | ||||||
|  |     pc->real = pc->imag = 0.0; | ||||||
|  |     if (PyInt_Check(obj)) { | ||||||
|  |         pc->real = PyInt_AS_LONG(obj); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     if (PyLong_Check(obj)) { | ||||||
|  |         pc->real = PyLong_AsDouble(obj); | ||||||
|  |         if (pc->real == -1.0 && PyErr_Occurred()) { | ||||||
|  |             *pobj = NULL; | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     if (PyFloat_Check(obj)) { | ||||||
|  |         pc->real = PyFloat_AsDouble(obj); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     Py_INCREF(Py_NotImplemented); | ||||||
|  |     *pobj = Py_NotImplemented; | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  | 		 | ||||||
|  | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| complex_add(PyComplexObject *v, PyComplexObject *w) | complex_add(PyComplexObject *v, PyComplexObject *w) | ||||||
| { | { | ||||||
|  | @ -502,24 +537,27 @@ complex_divmod(PyComplexObject *v, PyComplexObject *w) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z) | complex_pow(PyObject *v, PyObject *w, PyObject *z) | ||||||
| { | { | ||||||
| 	Py_complex p; | 	Py_complex p; | ||||||
| 	Py_complex exponent; | 	Py_complex exponent; | ||||||
| 	long int_exponent; | 	long int_exponent; | ||||||
|  | 	Py_complex a, b; | ||||||
|  |         TO_COMPLEX(v, a); | ||||||
|  |         TO_COMPLEX(w, b); | ||||||
| 
 | 
 | ||||||
|  	if ((PyObject *)z!=Py_None) { |  	if (z!=Py_None) { | ||||||
| 		PyErr_SetString(PyExc_ValueError, "complex modulo"); | 		PyErr_SetString(PyExc_ValueError, "complex modulo"); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	PyFPE_START_PROTECT("complex_pow", return 0) | 	PyFPE_START_PROTECT("complex_pow", return 0) | ||||||
| 	errno = 0; | 	errno = 0; | ||||||
| 	exponent = ((PyComplexObject*)w)->cval; | 	exponent = b; | ||||||
| 	int_exponent = (long)exponent.real; | 	int_exponent = (long)exponent.real; | ||||||
| 	if (exponent.imag == 0. && exponent.real == int_exponent) | 	if (exponent.imag == 0. && exponent.real == int_exponent) | ||||||
| 		p = c_powi(v->cval,int_exponent); | 		p = c_powi(a,int_exponent); | ||||||
| 	else | 	else | ||||||
| 		p = c_pow(v->cval,exponent); | 		p = c_pow(a,exponent); | ||||||
| 
 | 
 | ||||||
| 	PyFPE_END_PROTECT(p) | 	PyFPE_END_PROTECT(p) | ||||||
| 	Py_ADJUST_ERANGE2(p.real, p.imag); | 	Py_ADJUST_ERANGE2(p.real, p.imag); | ||||||
|  | @ -541,6 +579,10 @@ complex_int_div(PyComplexObject *v, PyComplexObject *w) | ||||||
| { | { | ||||||
| 	PyObject *t, *r; | 	PyObject *t, *r; | ||||||
| 	 | 	 | ||||||
|  | 	if (PyErr_Warn(PyExc_DeprecationWarning, | ||||||
|  | 		       "complex divmod(), // and % are deprecated") < 0) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
| 	t = complex_divmod(v, w); | 	t = complex_divmod(v, w); | ||||||
| 	if (t != NULL) { | 	if (t != NULL) { | ||||||
| 		r = PyTuple_GET_ITEM(t, 0); | 		r = PyTuple_GET_ITEM(t, 0); | ||||||
|  | @ -695,6 +737,11 @@ complex_conjugate(PyObject *self) | ||||||
| 	return PyComplex_FromCComplex(c); | 	return PyComplex_FromCComplex(c); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | PyDoc_STRVAR(complex_conjugate_doc, | ||||||
|  | "complex.conjugate() -> complex\n" | ||||||
|  | "\n" | ||||||
|  | "Returns the complex conjugate of its argument. (3-4j).conjugate() == 3+4j."); | ||||||
|  | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| complex_getnewargs(PyComplexObject *v) | complex_getnewargs(PyComplexObject *v) | ||||||
| { | { | ||||||
|  | @ -702,7 +749,8 @@ complex_getnewargs(PyComplexObject *v) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyMethodDef complex_methods[] = { | static PyMethodDef complex_methods[] = { | ||||||
| 	{"conjugate",	(PyCFunction)complex_conjugate,	METH_NOARGS}, | 	{"conjugate",	(PyCFunction)complex_conjugate,	METH_NOARGS, | ||||||
|  | 	 complex_conjugate_doc}, | ||||||
| 	{"__getnewargs__",	(PyCFunction)complex_getnewargs,	METH_NOARGS}, | 	{"__getnewargs__",	(PyCFunction)complex_getnewargs,	METH_NOARGS}, | ||||||
| 	{NULL,		NULL}		/* sentinel */ | 	{NULL,		NULL}		/* sentinel */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -986,9 +986,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) | ||||||
| 		 * bugs so we have to figure it out ourselves. | 		 * bugs so we have to figure it out ourselves. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (iw != floor(iw)) { | 		if (iw != floor(iw)) { | ||||||
| 			PyErr_SetString(PyExc_ValueError, "negative number " | 			/* Negative numbers raised to fractional powers
 | ||||||
| 				"cannot be raised to a fractional power"); | 			 * become complex. | ||||||
| 			return NULL; | 			 */ | ||||||
|  | 			return PyComplex_Type.tp_as_number->nb_power(v, w, z); | ||||||
| 		} | 		} | ||||||
| 		/* iw is an exact integer, albeit perhaps a very large one.
 | 		/* iw is an exact integer, albeit perhaps a very large one.
 | ||||||
| 		 * -1 raised to an exact integer should never be exceptional. | 		 * -1 raised to an exact integer should never be exceptional. | ||||||
|  | @ -1034,17 +1035,6 @@ float_neg(PyFloatObject *v) | ||||||
| 	return PyFloat_FromDouble(-v->ob_fval); | 	return PyFloat_FromDouble(-v->ob_fval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * |  | ||||||
| float_pos(PyFloatObject *v) |  | ||||||
| { |  | ||||||
| 	if (PyFloat_CheckExact(v)) { |  | ||||||
| 		Py_INCREF(v); |  | ||||||
| 		return (PyObject *)v; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 		return PyFloat_FromDouble(v->ob_fval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * | static PyObject * | ||||||
| float_abs(PyFloatObject *v) | float_abs(PyFloatObject *v) | ||||||
| { | { | ||||||
|  | @ -1083,14 +1073,7 @@ float_coerce(PyObject **pv, PyObject **pw) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| float_long(PyObject *v) | float_trunc(PyObject *v) | ||||||
| { |  | ||||||
| 	double x = PyFloat_AsDouble(v); |  | ||||||
| 	return PyLong_FromDouble(x); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * |  | ||||||
| float_int(PyObject *v) |  | ||||||
| { | { | ||||||
| 	double x = PyFloat_AsDouble(v); | 	double x = PyFloat_AsDouble(v); | ||||||
| 	double wholepart;	/* integral portion of x, rounded toward 0 */ | 	double wholepart;	/* integral portion of x, rounded toward 0 */ | ||||||
|  | @ -1115,6 +1098,54 @@ float_int(PyObject *v) | ||||||
| 	return PyLong_FromDouble(wholepart); | 	return PyLong_FromDouble(wholepart); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | float_round(PyObject *v, PyObject *args) | ||||||
|  | { | ||||||
|  | #define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ | ||||||
|  | 	double x; | ||||||
|  | 	double f; | ||||||
|  | 	double flr, cil; | ||||||
|  | 	double rounded; | ||||||
|  | 	int i; | ||||||
|  | 	int ndigits = UNDEF_NDIGITS; | ||||||
|  | 
 | ||||||
|  | 	if (!PyArg_ParseTuple(args, "|i", &ndigits)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	x = PyFloat_AsDouble(v); | ||||||
|  | 
 | ||||||
|  | 	if (ndigits != UNDEF_NDIGITS) { | ||||||
|  | 		f = 1.0; | ||||||
|  | 		i = abs(ndigits); | ||||||
|  | 		while  (--i >= 0) | ||||||
|  | 			f = f*10.0; | ||||||
|  | 		if (ndigits < 0) | ||||||
|  | 			x /= f; | ||||||
|  | 		else | ||||||
|  | 			x *= f; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flr = floor(x); | ||||||
|  | 	cil = ceil(x); | ||||||
|  | 
 | ||||||
|  | 	if (x-flr > 0.5) | ||||||
|  | 		rounded = cil; | ||||||
|  | 	else if (x-flr == 0.5)  | ||||||
|  | 		rounded = fmod(flr, 2) == 0 ? flr : cil; | ||||||
|  | 	else | ||||||
|  | 		rounded = flr; | ||||||
|  | 
 | ||||||
|  | 	if (ndigits != UNDEF_NDIGITS) { | ||||||
|  | 		if (ndigits < 0) | ||||||
|  | 			rounded *= f; | ||||||
|  | 		else | ||||||
|  | 			rounded /= f; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return PyFloat_FromDouble(rounded); | ||||||
|  | #undef UNDEF_NDIGITS | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| float_float(PyObject *v) | float_float(PyObject *v) | ||||||
| { | { | ||||||
|  | @ -1302,7 +1333,20 @@ PyDoc_STRVAR(float_setformat_doc, | ||||||
| "Overrides the automatic determination of C-level floating point type.\n" | "Overrides the automatic determination of C-level floating point type.\n" | ||||||
| "This affects how floats are converted to and from binary strings."); | "This affects how floats are converted to and from binary strings."); | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | float_getzero(PyObject *v, void *closure) | ||||||
|  | { | ||||||
|  | 	return PyFloat_FromDouble(0.0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static PyMethodDef float_methods[] = { | static PyMethodDef float_methods[] = { | ||||||
|  |   	{"conjugate",	(PyCFunction)float_float,	METH_NOARGS, | ||||||
|  | 	 "Returns self, the complex conjugate of any float."}, | ||||||
|  | 	{"__trunc__",	(PyCFunction)float_trunc, METH_NOARGS, | ||||||
|  |          "Returns the Integral closest to x between 0 and x."}, | ||||||
|  | 	{"__round__",	(PyCFunction)float_round, METH_VARARGS, | ||||||
|  |          "Returns the Integral closest to x, rounding half toward even.\n" | ||||||
|  |          "When an argument is passed, works like built-in round(x, ndigits)."}, | ||||||
| 	{"__getnewargs__",	(PyCFunction)float_getnewargs,	METH_NOARGS}, | 	{"__getnewargs__",	(PyCFunction)float_getnewargs,	METH_NOARGS}, | ||||||
| 	{"__getformat__",	(PyCFunction)float_getformat,	 | 	{"__getformat__",	(PyCFunction)float_getformat,	 | ||||||
| 	 METH_O|METH_CLASS,		float_getformat_doc}, | 	 METH_O|METH_CLASS,		float_getformat_doc}, | ||||||
|  | @ -1311,6 +1355,18 @@ static PyMethodDef float_methods[] = { | ||||||
| 	{NULL,		NULL}		/* sentinel */ | 	{NULL,		NULL}		/* sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static PyGetSetDef float_getset[] = { | ||||||
|  |     {"real",  | ||||||
|  |      (getter)float_float, (setter)NULL, | ||||||
|  |      "the real part of a complex number", | ||||||
|  |      NULL}, | ||||||
|  |     {"imag",  | ||||||
|  |      (getter)float_getzero, (setter)NULL, | ||||||
|  |      "the imaginary part of a complex number", | ||||||
|  |      NULL}, | ||||||
|  |     {NULL}  /* Sentinel */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| PyDoc_STRVAR(float_doc, | PyDoc_STRVAR(float_doc, | ||||||
| "float(x) -> floating point number\n\
 | "float(x) -> floating point number\n\
 | ||||||
| \n\ | \n\ | ||||||
|  | @ -1326,7 +1382,7 @@ static PyNumberMethods float_as_number = { | ||||||
| 	float_divmod, 	/*nb_divmod*/ | 	float_divmod, 	/*nb_divmod*/ | ||||||
| 	float_pow, 	/*nb_power*/ | 	float_pow, 	/*nb_power*/ | ||||||
| 	(unaryfunc)float_neg, /*nb_negative*/ | 	(unaryfunc)float_neg, /*nb_negative*/ | ||||||
| 	(unaryfunc)float_pos, /*nb_positive*/ | 	(unaryfunc)float_float, /*nb_positive*/ | ||||||
| 	(unaryfunc)float_abs, /*nb_absolute*/ | 	(unaryfunc)float_abs, /*nb_absolute*/ | ||||||
| 	(inquiry)float_nonzero, /*nb_nonzero*/ | 	(inquiry)float_nonzero, /*nb_nonzero*/ | ||||||
| 	0,		/*nb_invert*/ | 	0,		/*nb_invert*/ | ||||||
|  | @ -1336,8 +1392,8 @@ static PyNumberMethods float_as_number = { | ||||||
| 	0,		/*nb_xor*/ | 	0,		/*nb_xor*/ | ||||||
| 	0,		/*nb_or*/ | 	0,		/*nb_or*/ | ||||||
| 	float_coerce, 	/*nb_coerce*/ | 	float_coerce, 	/*nb_coerce*/ | ||||||
| 	float_int, 	/*nb_int*/ | 	float_trunc, 	/*nb_int*/ | ||||||
| 	float_long, 	/*nb_long*/ | 	float_trunc, 	/*nb_long*/ | ||||||
| 	float_float,	/*nb_float*/ | 	float_float,	/*nb_float*/ | ||||||
| 	0,		/* nb_oct */ | 	0,		/* nb_oct */ | ||||||
| 	0,		/* nb_hex */ | 	0,		/* nb_hex */ | ||||||
|  | @ -1389,7 +1445,7 @@ PyTypeObject PyFloat_Type = { | ||||||
| 	0,					/* tp_iternext */ | 	0,					/* tp_iternext */ | ||||||
| 	float_methods,				/* tp_methods */ | 	float_methods,				/* tp_methods */ | ||||||
| 	0,					/* tp_members */ | 	0,					/* tp_members */ | ||||||
| 	0,					/* tp_getset */ | 	float_getset,				/* tp_getset */ | ||||||
| 	0,					/* tp_base */ | 	0,					/* tp_base */ | ||||||
| 	0,					/* tp_dict */ | 	0,					/* tp_dict */ | ||||||
| 	0,					/* tp_descr_get */ | 	0,					/* tp_descr_get */ | ||||||
|  |  | ||||||
|  | @ -4,6 +4,8 @@ | ||||||
| #include "Python.h" | #include "Python.h" | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| 
 | 
 | ||||||
|  | static PyObject *int_int(PyIntObject *v); | ||||||
|  | 
 | ||||||
| long | long | ||||||
| PyInt_GetMax(void) | PyInt_GetMax(void) | ||||||
| { | { | ||||||
|  | @ -782,22 +784,11 @@ int_neg(PyIntObject *v) | ||||||
| 	return PyInt_FromLong(-a); | 	return PyInt_FromLong(-a); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * |  | ||||||
| int_pos(PyIntObject *v) |  | ||||||
| { |  | ||||||
| 	if (PyInt_CheckExact(v)) { |  | ||||||
| 		Py_INCREF(v); |  | ||||||
| 		return (PyObject *)v; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 		return PyInt_FromLong(v->ob_ival); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * | static PyObject * | ||||||
| int_abs(PyIntObject *v) | int_abs(PyIntObject *v) | ||||||
| { | { | ||||||
| 	if (v->ob_ival >= 0) | 	if (v->ob_ival >= 0) | ||||||
| 		return int_pos(v); | 		return int_int(v); | ||||||
| 	else | 	else | ||||||
| 		return int_neg(v); | 		return int_neg(v); | ||||||
| } | } | ||||||
|  | @ -827,7 +818,7 @@ int_lshift(PyIntObject *v, PyIntObject *w) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	if (a == 0 || b == 0) | 	if (a == 0 || b == 0) | ||||||
| 		return int_pos(v); | 		return int_int(v); | ||||||
| 	if (b >= LONG_BIT) { | 	if (b >= LONG_BIT) { | ||||||
| 		vv = PyLong_FromLong(PyInt_AS_LONG(v)); | 		vv = PyLong_FromLong(PyInt_AS_LONG(v)); | ||||||
| 		if (vv == NULL) | 		if (vv == NULL) | ||||||
|  | @ -871,7 +862,7 @@ int_rshift(PyIntObject *v, PyIntObject *w) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	if (a == 0 || b == 0) | 	if (a == 0 || b == 0) | ||||||
| 		return int_pos(v); | 		return int_int(v); | ||||||
| 	if (b >= LONG_BIT) { | 	if (b >= LONG_BIT) { | ||||||
| 		if (a < 0) | 		if (a < 0) | ||||||
| 			a = -1; | 			a = -1; | ||||||
|  | @ -1060,11 +1051,72 @@ int_getnewargs(PyIntObject *v) | ||||||
| 	return Py_BuildValue("(l)", v->ob_ival); | 	return Py_BuildValue("(l)", v->ob_ival); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | int_getN(PyIntObject *v, void *context) { | ||||||
|  | 	return PyInt_FromLong((intptr_t)context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | int_round(PyObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  | #define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ | ||||||
|  | 	int ndigits = UNDEF_NDIGITS; | ||||||
|  | 	double x; | ||||||
|  | 	PyObject *res; | ||||||
|  | 	 | ||||||
|  | 	if (!PyArg_ParseTuple(args, "|i", &ndigits)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	if (ndigits == UNDEF_NDIGITS) | ||||||
|  |           return int_float((PyIntObject *)self); | ||||||
|  | 
 | ||||||
|  | 	/* If called with two args, defer to float.__round__(). */ | ||||||
|  | 	x = (double) PyInt_AS_LONG(self); | ||||||
|  | 	self = PyFloat_FromDouble(x); | ||||||
|  | 	if (self == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	res = PyObject_CallMethod(self, "__round__", "i", ndigits); | ||||||
|  | 	Py_DECREF(self); | ||||||
|  | 	return res; | ||||||
|  | #undef UNDEF_NDIGITS | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static PyMethodDef int_methods[] = { | static PyMethodDef int_methods[] = { | ||||||
|  | 	{"conjugate",	(PyCFunction)int_int,	METH_NOARGS, | ||||||
|  | 	 "Returns self, the complex conjugate of any int."}, | ||||||
|  | 	{"__trunc__",	(PyCFunction)int_int,	METH_NOARGS, | ||||||
|  |          "Truncating an Integral returns itself."}, | ||||||
|  | 	{"__floor__",	(PyCFunction)int_int,	METH_NOARGS, | ||||||
|  |          "Flooring an Integral returns itself."}, | ||||||
|  | 	{"__ceil__",	(PyCFunction)int_int,	METH_NOARGS, | ||||||
|  |          "Ceiling of an Integral returns itself."}, | ||||||
|  | 	{"__round__",	(PyCFunction)int_round, METH_VARARGS, | ||||||
|  |          "Rounding an Integral returns itself.\n" | ||||||
|  | 	 "Rounding with an ndigits arguments defers to float.__round__."}, | ||||||
| 	{"__getnewargs__",	(PyCFunction)int_getnewargs,	METH_NOARGS}, | 	{"__getnewargs__",	(PyCFunction)int_getnewargs,	METH_NOARGS}, | ||||||
| 	{NULL,		NULL}		/* sentinel */ | 	{NULL,		NULL}		/* sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static PyGetSetDef int_getset[] = { | ||||||
|  | 	{"real",  | ||||||
|  | 	 (getter)int_int, (setter)NULL, | ||||||
|  | 	 "the real part of a complex number", | ||||||
|  | 	 NULL}, | ||||||
|  | 	{"imag",  | ||||||
|  | 	 (getter)int_getN, (setter)NULL, | ||||||
|  | 	 "the imaginary part of a complex number", | ||||||
|  | 	 (void*)0}, | ||||||
|  | 	{"numerator",  | ||||||
|  | 	 (getter)int_int, (setter)NULL, | ||||||
|  | 	 "the numerator of a rational number in lowest terms", | ||||||
|  | 	 NULL}, | ||||||
|  | 	{"denominator",  | ||||||
|  | 	 (getter)int_getN, (setter)NULL, | ||||||
|  | 	 "the denominator of a rational number in lowest terms", | ||||||
|  | 	 (void*)1}, | ||||||
|  | 	{NULL}  /* Sentinel */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| PyDoc_STRVAR(int_doc, | PyDoc_STRVAR(int_doc, | ||||||
| "int(x[, base]) -> integer\n\
 | "int(x[, base]) -> integer\n\
 | ||||||
| \n\ | \n\ | ||||||
|  | @ -1085,7 +1137,7 @@ static PyNumberMethods int_as_number = { | ||||||
| 	(binaryfunc)int_divmod,	/*nb_divmod*/ | 	(binaryfunc)int_divmod,	/*nb_divmod*/ | ||||||
| 	(ternaryfunc)int_pow,	/*nb_power*/ | 	(ternaryfunc)int_pow,	/*nb_power*/ | ||||||
| 	(unaryfunc)int_neg,	/*nb_negative*/ | 	(unaryfunc)int_neg,	/*nb_negative*/ | ||||||
| 	(unaryfunc)int_pos,	/*nb_positive*/ | 	(unaryfunc)int_int,	/*nb_positive*/ | ||||||
| 	(unaryfunc)int_abs,	/*nb_absolute*/ | 	(unaryfunc)int_abs,	/*nb_absolute*/ | ||||||
| 	(inquiry)int_nonzero,	/*nb_nonzero*/ | 	(inquiry)int_nonzero,	/*nb_nonzero*/ | ||||||
| 	(unaryfunc)int_invert,	/*nb_invert*/ | 	(unaryfunc)int_invert,	/*nb_invert*/ | ||||||
|  | @ -1149,7 +1201,7 @@ PyTypeObject PyInt_Type = { | ||||||
| 	0,					/* tp_iternext */ | 	0,					/* tp_iternext */ | ||||||
| 	int_methods,				/* tp_methods */ | 	int_methods,				/* tp_methods */ | ||||||
| 	0,					/* tp_members */ | 	0,					/* tp_members */ | ||||||
| 	0,					/* tp_getset */ | 	int_getset,				/* tp_getset */ | ||||||
| 	0,					/* tp_base */ | 	0,					/* tp_base */ | ||||||
| 	0,					/* tp_dict */ | 	0,					/* tp_dict */ | ||||||
| 	0,					/* tp_descr_get */ | 	0,					/* tp_descr_get */ | ||||||
|  |  | ||||||
|  | @ -1716,7 +1716,7 @@ PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) | ||||||
| /* forward */ | /* forward */ | ||||||
| static PyLongObject *x_divrem | static PyLongObject *x_divrem | ||||||
| 	(PyLongObject *, PyLongObject *, PyLongObject **); | 	(PyLongObject *, PyLongObject *, PyLongObject **); | ||||||
| static PyObject *long_pos(PyLongObject *); | static PyObject *long_long(PyObject *v); | ||||||
| static int long_divrem(PyLongObject *, PyLongObject *, | static int long_divrem(PyLongObject *, PyLongObject *, | ||||||
| 	PyLongObject **, PyLongObject **); | 	PyLongObject **, PyLongObject **); | ||||||
| 
 | 
 | ||||||
|  | @ -2905,17 +2905,6 @@ long_invert(PyLongObject *v) | ||||||
| 	return (PyObject *)x; | 	return (PyObject *)x; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * |  | ||||||
| long_pos(PyLongObject *v) |  | ||||||
| { |  | ||||||
| 	if (PyLong_CheckExact(v)) { |  | ||||||
| 		Py_INCREF(v); |  | ||||||
| 		return (PyObject *)v; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 		return _PyLong_Copy(v); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * | static PyObject * | ||||||
| long_neg(PyLongObject *v) | long_neg(PyLongObject *v) | ||||||
| { | { | ||||||
|  | @ -2937,7 +2926,7 @@ long_abs(PyLongObject *v) | ||||||
| 	if (v->ob_size < 0) | 	if (v->ob_size < 0) | ||||||
| 		return long_neg(v); | 		return long_neg(v); | ||||||
| 	else | 	else | ||||||
| 		return long_pos(v); | 		return long_long((PyObject *)v); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
|  | @ -3373,11 +3362,74 @@ long_getnewargs(PyLongObject *v) | ||||||
| 	return Py_BuildValue("(N)", _PyLong_Copy(v)); | 	return Py_BuildValue("(N)", _PyLong_Copy(v)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | long_getN(PyLongObject *v, void *context) { | ||||||
|  | 	return PyLong_FromLong((intptr_t)context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | long_round(PyObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  | #define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ | ||||||
|  | 	int ndigits = UNDEF_NDIGITS; | ||||||
|  | 	double x; | ||||||
|  | 	PyObject *res; | ||||||
|  | 	 | ||||||
|  | 	if (!PyArg_ParseTuple(args, "|i", &ndigits)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	if (ndigits == UNDEF_NDIGITS) | ||||||
|  | 		return long_float(self); | ||||||
|  | 
 | ||||||
|  | 	/* If called with two args, defer to float.__round__(). */ | ||||||
|  | 	x = PyLong_AsDouble(self); | ||||||
|  | 	if (x == -1.0 && PyErr_Occurred()) | ||||||
|  | 		return NULL; | ||||||
|  | 	self = PyFloat_FromDouble(x); | ||||||
|  | 	if (self == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	res = PyObject_CallMethod(self, "__round__", "i", ndigits); | ||||||
|  | 	Py_DECREF(self); | ||||||
|  | 	return res; | ||||||
|  | #undef UNDEF_NDIGITS | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static PyMethodDef long_methods[] = { | static PyMethodDef long_methods[] = { | ||||||
|  | 	{"conjugate",	(PyCFunction)long_long,	METH_NOARGS, | ||||||
|  | 	 "Returns self, the complex conjugate of any long."}, | ||||||
|  | 	{"__trunc__",	(PyCFunction)long_long,	METH_NOARGS, | ||||||
|  |          "Truncating an Integral returns itself."}, | ||||||
|  | 	{"__floor__",	(PyCFunction)long_long,	METH_NOARGS, | ||||||
|  |          "Flooring an Integral returns itself."}, | ||||||
|  | 	{"__ceil__",	(PyCFunction)long_long,	METH_NOARGS, | ||||||
|  |          "Ceiling of an Integral returns itself."}, | ||||||
|  | 	{"__round__",	(PyCFunction)long_round, METH_VARARGS, | ||||||
|  |          "Rounding an Integral returns itself.\n" | ||||||
|  | 	 "Rounding with an ndigits arguments defers to float.__round__."}, | ||||||
| 	{"__getnewargs__",	(PyCFunction)long_getnewargs,	METH_NOARGS}, | 	{"__getnewargs__",	(PyCFunction)long_getnewargs,	METH_NOARGS}, | ||||||
| 	{NULL,		NULL}		/* sentinel */ | 	{NULL,		NULL}		/* sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static PyGetSetDef long_getset[] = { | ||||||
|  |     {"real",  | ||||||
|  |      (getter)long_long, (setter)NULL, | ||||||
|  |      "the real part of a complex number", | ||||||
|  |      NULL}, | ||||||
|  |     {"imag",  | ||||||
|  |      (getter)long_getN, (setter)NULL, | ||||||
|  |      "the imaginary part of a complex number", | ||||||
|  |      (void*)0}, | ||||||
|  |     {"numerator",  | ||||||
|  |      (getter)long_long, (setter)NULL, | ||||||
|  |      "the numerator of a rational number in lowest terms", | ||||||
|  |      NULL}, | ||||||
|  |     {"denominator",  | ||||||
|  |      (getter)long_getN, (setter)NULL, | ||||||
|  |      "the denominator of a rational number in lowest terms", | ||||||
|  |      (void*)1}, | ||||||
|  |     {NULL}  /* Sentinel */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| PyDoc_STRVAR(long_doc, | PyDoc_STRVAR(long_doc, | ||||||
| "long(x[, base]) -> integer\n\
 | "long(x[, base]) -> integer\n\
 | ||||||
| \n\ | \n\ | ||||||
|  | @ -3396,7 +3448,7 @@ static PyNumberMethods long_as_number = { | ||||||
| 			long_divmod,	/*nb_divmod*/ | 			long_divmod,	/*nb_divmod*/ | ||||||
| 			long_pow,	/*nb_power*/ | 			long_pow,	/*nb_power*/ | ||||||
| 	(unaryfunc) 	long_neg,	/*nb_negative*/ | 	(unaryfunc) 	long_neg,	/*nb_negative*/ | ||||||
| 	(unaryfunc) 	long_pos,	/*tp_positive*/ | 	(unaryfunc) 	long_long,	/*tp_positive*/ | ||||||
| 	(unaryfunc) 	long_abs,	/*tp_absolute*/ | 	(unaryfunc) 	long_abs,	/*tp_absolute*/ | ||||||
| 	(inquiry)	long_nonzero,	/*tp_nonzero*/ | 	(inquiry)	long_nonzero,	/*tp_nonzero*/ | ||||||
| 	(unaryfunc)	long_invert,	/*nb_invert*/ | 	(unaryfunc)	long_invert,	/*nb_invert*/ | ||||||
|  | @ -3461,7 +3513,7 @@ PyTypeObject PyLong_Type = { | ||||||
| 	0,					/* tp_iternext */ | 	0,					/* tp_iternext */ | ||||||
| 	long_methods,				/* tp_methods */ | 	long_methods,				/* tp_methods */ | ||||||
| 	0,					/* tp_members */ | 	0,					/* tp_members */ | ||||||
| 	0,					/* tp_getset */ | 	long_getset,				/* tp_getset */ | ||||||
| 	0,					/* tp_base */ | 	0,					/* tp_base */ | ||||||
| 	0,					/* tp_dict */ | 	0,					/* tp_dict */ | ||||||
| 	0,					/* tp_descr_get */ | 	0,					/* tp_descr_get */ | ||||||
|  |  | ||||||
|  | @ -1926,39 +1926,31 @@ For most object types, eval(repr(object)) == object."); | ||||||
| static PyObject * | static PyObject * | ||||||
| builtin_round(PyObject *self, PyObject *args, PyObject *kwds) | builtin_round(PyObject *self, PyObject *args, PyObject *kwds) | ||||||
| { | { | ||||||
| 	double number; | #define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ | ||||||
| 	double f; | 	int ndigits = UNDEF_NDIGITS; | ||||||
| 	int ndigits = 0; |  | ||||||
| 	int i; |  | ||||||
| 	static char *kwlist[] = {"number", "ndigits", 0}; | 	static char *kwlist[] = {"number", "ndigits", 0}; | ||||||
|  | 	PyObject *number; | ||||||
| 
 | 
 | ||||||
| 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|i:round", | 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:round", | ||||||
|                 kwlist, &number, &ndigits)) |                 kwlist, &number, &ndigits)) | ||||||
|                 return NULL; |                 return NULL; | ||||||
| 	f = 1.0; | 
 | ||||||
| 	i = abs(ndigits); |         // The py3k branch gets better errors for this by using
 | ||||||
| 	while  (--i >= 0) |         // _PyType_Lookup(), but since float's mro isn't set in py2.6,
 | ||||||
| 		f = f*10.0; |         // we just use PyObject_CallMethod here.
 | ||||||
| 	if (ndigits < 0) |         if (ndigits == UNDEF_NDIGITS) | ||||||
| 		number /= f; |                 return PyObject_CallMethod(number, "__round__", ""); | ||||||
|         else |         else | ||||||
| 		number *= f; |                 return PyObject_CallMethod(number, "__round__", "i", ndigits); | ||||||
| 	if (number >= 0.0) | #undef UNDEF_NDIGITS | ||||||
| 		number = floor(number + 0.5); |  | ||||||
| 	else |  | ||||||
| 		number = ceil(number - 0.5); |  | ||||||
| 	if (ndigits < 0) |  | ||||||
| 		number *= f; |  | ||||||
| 	else |  | ||||||
| 		number /= f; |  | ||||||
| 	return PyFloat_FromDouble(number); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| PyDoc_STRVAR(round_doc, | PyDoc_STRVAR(round_doc, | ||||||
| "round(number[, ndigits]) -> floating point number\n\
 | "round(number[, ndigits]) -> floating point number\n\
 | ||||||
| \n\ | \n\ | ||||||
| Round a number to a given precision in decimal digits (default 0 digits).\n\ | Round a number to a given precision in decimal digits (default 0 digits).\n\ | ||||||
| This always returns a floating point number.  Precision may be negative."); | This returns an int when called with one argument, otherwise a float.\n\ | ||||||
|  | Precision may be negative."); | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds) | builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds) | ||||||
|  | @ -2039,6 +2031,20 @@ PyDoc_STRVAR(vars_doc, | ||||||
| Without arguments, equivalent to locals().\n\ | Without arguments, equivalent to locals().\n\ | ||||||
| With an argument, equivalent to object.__dict__."); | With an argument, equivalent to object.__dict__."); | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | builtin_trunc(PyObject *self, PyObject *number) | ||||||
|  | { | ||||||
|  |         // XXX: The py3k branch gets better errors for this by using
 | ||||||
|  |         // _PyType_Lookup(), but since float's mro isn't set in py2.6,
 | ||||||
|  |         // we just use PyObject_CallMethod here.
 | ||||||
|  | 	return PyObject_CallMethod(number, "__trunc__", ""); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(trunc_doc, | ||||||
|  | "trunc(Real) -> Integral\n\
 | ||||||
|  | \n\ | ||||||
|  | returns the integral closest to x between 0 and x."); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| static PyObject* | static PyObject* | ||||||
| builtin_sum(PyObject *self, PyObject *args) | builtin_sum(PyObject *self, PyObject *args) | ||||||
|  | @ -2387,6 +2393,7 @@ static PyMethodDef builtin_methods[] = { | ||||||
|  	{"unichr",	builtin_unichr,     METH_VARARGS, unichr_doc}, |  	{"unichr",	builtin_unichr,     METH_VARARGS, unichr_doc}, | ||||||
| #endif | #endif | ||||||
|  	{"vars",	builtin_vars,       METH_VARARGS, vars_doc}, |  	{"vars",	builtin_vars,       METH_VARARGS, vars_doc}, | ||||||
|  |  	{"trunc",	builtin_trunc,      METH_O, trunc_doc}, | ||||||
|   	{"zip",         builtin_zip,        METH_VARARGS, zip_doc}, |   	{"zip",         builtin_zip,        METH_VARARGS, zip_doc}, | ||||||
| 	{NULL,		NULL}, | 	{NULL,		NULL}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeffrey Yasskin
						Jeffrey Yasskin