Skip to content

Commit

Permalink
Merged revisions 60475-60479,60481-60488 via svnmerge from
Browse files Browse the repository at this point in the history
svn+ssh://[email protected]/python/trunk

........
  r60482 | raymond.hettinger | 2008-01-31 23:07:16 +0100 (Thu, 31 Jan 2008) | 1 line

  Minor wordsmithing on docstring
........
  r60483 | mark.dickinson | 2008-01-31 23:17:37 +0100 (Thu, 31 Jan 2008) | 5 lines

  Issue #1678380.  Fix a bug that identifies 0j and -0j when they appear
  in the same code unit. The fix is essentially the same as the fix for a
  previous bug identifying 0. and -0.
........
  r60484 | christian.heimes | 2008-02-01 00:08:23 +0100 (Fri, 01 Feb 2008) | 1 line

  Fixed bug #1983: Return from fork() is pid_t, not int
........
  r60486 | jeffrey.yasskin | 2008-02-01 07:22:46 +0100 (Fri, 01 Feb 2008) | 4 lines

  Move __builtins__.trunc() to math.trunc() per
  http://mail.python.org/pipermail/python-dev/2008-January/076626.html and issue
  1965.
........
  r60487 | jeffrey.yasskin | 2008-02-01 08:05:46 +0100 (Fri, 01 Feb 2008) | 3 lines

  Roll back r60248. It's useful to encourage users not to change Rational
  instances.
........
  r60488 | neal.norwitz | 2008-02-01 08:22:59 +0100 (Fri, 01 Feb 2008) | 1 line

  Fix refleak
........
  • Loading branch information
tiran committed Feb 1, 2008
1 parent a771209 commit 400adb0
Show file tree
Hide file tree
Showing 18 changed files with 597 additions and 117 deletions.
6 changes: 0 additions & 6 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1059,12 +1059,6 @@ available. They are listed here in alphabetical order.
operators such as ``super(C, self)[name]``.


.. function:: trunc(x)

Return the :class:`Real` value *x* truncated to an :class:`Integral` (usually
a long integer). Delegates to ``x.__trunc__()``.


.. function:: tuple([iterable])

Return a tuple whose items are the same and in the same order as *iterable*'s
Expand Down
8 changes: 8 additions & 0 deletions Doc/library/math.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ Number-theoretic and representation functions:
Return the fractional and integer parts of *x*. Both results carry the sign of
*x*, and both are floats.


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

Note that :func:`frexp` and :func:`modf` have a different call/return pattern
than their C equivalents: they take a single argument and return a pair of
values, rather than returning their second return value through an 'output
Expand Down
6 changes: 5 additions & 1 deletion Include/pyport.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ typedef Py_intptr_t Py_ssize_t;
/* Smallest negative value of type Py_ssize_t. */
#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1)

#if SIZEOF_PID_T > SIZEOF_LONG
# error "Python doesn't support sizeof(pid_t) > sizeof(long)"
#endif

/* PY_FORMAT_SIZE_T is a platform-specific modifier for use in a printf
* format to convert an argument with the width of a size_t or Py_ssize_t.
* C99 introduced "z" for this purpose, but not all platforms support that;
Expand Down Expand Up @@ -550,7 +554,7 @@ extern char * _getpty(int *, int, mode_t, int);
functions, even though they are included in libutil. */
#include <termios.h>
extern int openpty(int *, int *, char *, struct termios *, struct winsize *);
extern int forkpty(int *, char *, struct termios *, struct winsize *);
extern pid_t forkpty(int *, char *, struct termios *, struct winsize *);
#endif /* !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) */
#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) */

Expand Down
29 changes: 18 additions & 11 deletions Lib/rational.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Rational(RationalAbc):
"""

__slots__ = ('numerator', 'denominator')
__slots__ = ('_numerator', '_denominator')

# We're immutable, so use __new__ not __init__
def __new__(cls, numerator=0, denominator=1):
Expand Down Expand Up @@ -92,8 +92,8 @@ def __new__(cls, numerator=0, denominator=1):
raise ZeroDivisionError('Rational(%s, 0)' % numerator)

g = gcd(numerator, denominator)
self.numerator = int(numerator // g)
self.denominator = int(denominator // g)
self._numerator = int(numerator // g)
self._denominator = int(denominator // g)
return self

@classmethod
Expand Down Expand Up @@ -167,6 +167,14 @@ def approximate(self, max_denominator):
result = new
return result

@property
def numerator(a):
return a._numerator

@property
def denominator(a):
return a._denominator

def __repr__(self):
"""repr(self)"""
return ('Rational(%r,%r)' % (self.numerator, self.denominator))
Expand All @@ -192,20 +200,20 @@ def _operator_fallbacks(monomorphic_operator, fallback_operator):
Rational, that means that we define __add__ and __radd__ as:
def __add__(self, other):
# Both types have numerators/denominator attributes,
# so do the operation directly
if isinstance(other, (int, Rational)):
# Do the real operation.
return Rational(self.numerator * other.denominator +
other.numerator * self.denominator,
self.denominator * other.denominator)
# float and complex don't follow this protocol, and
# Rational knows about them, so special case them.
# float and complex don't have those operations, but we
# know about those types, so special case them.
elif isinstance(other, float):
return float(self) + other
elif isinstance(other, complex):
return complex(self) + other
else:
# Let the other type take over.
return NotImplemented
# Let the other type take over.
return NotImplemented
def __radd__(self, other):
# radd handles more types than add because there's
Expand All @@ -218,8 +226,7 @@ def __radd__(self, other):
return float(other) + float(self)
elif isinstance(other, Complex):
return complex(other) + complex(self)
else:
return NotImplemented
return NotImplemented
There are 5 different cases for a mixed-type addition on
Expand Down
12 changes: 7 additions & 5 deletions Lib/test/test_abstract_numbers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Unit tests for numbers.py."""

import math
import operator
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
from numbers import Exact, Inexact
from numbers import Number
from test import test_support

class TestNumbers(unittest.TestCase):
def test_int(self):
Expand Down Expand Up @@ -37,7 +38,8 @@ def test_complex(self):
self.failUnless(issubclass(complex, Inexact))

c1, c2 = complex(3, 2), complex(4,1)
self.assertRaises(TypeError, trunc, c1)
# XXX: This is not ideal, but see the comment in math_trunc().
self.assertRaises(TypeError, math.trunc, c1)
self.assertRaises(TypeError, operator.mod, c1, c2)
self.assertRaises(TypeError, divmod, c1, c2)
self.assertRaises(TypeError, operator.floordiv, c1, c2)
Expand Down
31 changes: 0 additions & 31 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1643,37 +1643,6 @@ def __getitem__(self, index):
raise ValueError
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:
def __trunc__(self):
return 23

class TestNoTrunc:
pass

self.assertEqual(trunc(TestTrunc()), 23)

self.assertRaises(TypeError, trunc)
self.assertRaises(TypeError, trunc, 1, 2)
self.assertRaises(TypeError, trunc, TestNoTrunc())

t = TestNoTrunc()
t.__trunc__ = lambda *args: args
self.assertRaises(TypeError, trunc, t)
self.assertRaises(TypeError, trunc, t, 0)

def test_tuple(self):
self.assertEqual(tuple(()), ())
t0_3 = (0, 1, 2, 3)
Expand Down
7 changes: 7 additions & 0 deletions Lib/test/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,13 @@ def test_file(self):
except (OSError, IOError):
pass

if float.__getformat__("double").startswith("IEEE"):
def test_plus_minus_0j(self):
# test that -0j and 0j literals are not identified
z1, z2 = 0j, -0j
self.assertEquals(atan2(z1.imag, -1.), atan2(0., -1.))
self.assertEquals(atan2(z2.imag, -1.), atan2(-0., -1.))

def test_main():
test_support.run_unittest(ComplexTest)

Expand Down
5 changes: 3 additions & 2 deletions Lib/test/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
"""
from __future__ import with_statement

import unittest
import glob
import math
import os, sys
import pickle, copy
import unittest
from decimal import *
from test.test_support import (TestSkipped, run_unittest, run_doctest,
is_resource_enabled)
Expand Down Expand Up @@ -1213,7 +1214,7 @@ def test_trunc(self):
# should work the same as to_integral in the ROUND_DOWN mode
d = Decimal(s)
r = d.to_integral(ROUND_DOWN)
self.assertEqual(Decimal(trunc(d)), r)
self.assertEqual(Decimal(math.trunc(d)), r)

class ContextAPItests(unittest.TestCase):

Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,38 @@ def testTanh(self):
self.ftest('tanh(0)', math.tanh(0), 0)
self.ftest('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0)

def test_trunc(self):
self.assertEqual(math.trunc(1), 1)
self.assertEqual(math.trunc(-1), -1)
self.assertEqual(type(math.trunc(1)), int)
self.assertEqual(type(math.trunc(1.5)), int)
self.assertEqual(math.trunc(1.5), 1)
self.assertEqual(math.trunc(-1.5), -1)
self.assertEqual(math.trunc(1.999999), 1)
self.assertEqual(math.trunc(-1.999999), -1)
self.assertEqual(math.trunc(-0.999999), -0)
self.assertEqual(math.trunc(-100.999), -100)

class TestTrunc(object):
def __trunc__(self):
return 23

class TestNoTrunc(object):
pass

self.assertEqual(math.trunc(TestTrunc()), 23)

self.assertRaises(TypeError, math.trunc)
self.assertRaises(TypeError, math.trunc, 1, 2)
self.assertRaises(TypeError, math.trunc, TestNoTrunc())

# XXX Doesn't work because the method is looked up on
# the type only.
#t = TestNoTrunc()
#t.__trunc__ = lambda *args: args
#self.assertEquals((), math.trunc(t))
#self.assertRaises(TypeError, math.trunc, t, 0)

def testCopysign(self):
self.assertEqual(math.copysign(1, 42), 1.0)
self.assertEqual(math.copysign(0., 42), 0.0)
Expand Down
23 changes: 17 additions & 6 deletions Lib/test/test_rational.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ def testImmutable(self):
r.__init__(2, 15)
self.assertEquals((7, 3), _components(r))

self.assertRaises(AttributeError, setattr, r, 'numerator', 12)
self.assertRaises(AttributeError, setattr, r, 'denominator', 6)
self.assertEquals((7, 3), _components(r))

# But if you _really_ need to:
r._numerator = 4
r._denominator = 2
self.assertEquals((4, 2), _components(r))
# Which breaks some important operations:
self.assertNotEquals(R(4, 2), r)

def testFromFloat(self):
self.assertRaisesMessage(
TypeError, "Rational.from_float() only takes floats, not 3 (int)",
Expand Down Expand Up @@ -193,7 +204,7 @@ def testApproximateFrom(self):
self.assertEqual(R.from_float(0.0).approximate(10000), R(0))

def testConversions(self):
self.assertTypedEquals(-1, trunc(R(-11, 10)))
self.assertTypedEquals(-1, math.trunc(R(-11, 10)))
self.assertTypedEquals(-2, math.floor(R(-11, 10)))
self.assertTypedEquals(-1, math.ceil(R(-11, 10)))
self.assertTypedEquals(-1, math.ceil(R(-10, 10)))
Expand Down Expand Up @@ -337,11 +348,11 @@ def testBigFloatComparisons(self):
# Because 10**23 can't be represented exactly as a float:
self.assertFalse(R(10**23) == float(10**23))
# The first test demonstrates why these are important.
self.assertFalse(1e23 < float(R(trunc(1e23) + 1)))
self.assertTrue(1e23 < R(trunc(1e23) + 1))
self.assertFalse(1e23 <= R(trunc(1e23) - 1))
self.assertTrue(1e23 > R(trunc(1e23) - 1))
self.assertFalse(1e23 >= R(trunc(1e23) + 1))
self.assertFalse(1e23 < float(R(math.trunc(1e23) + 1)))
self.assertTrue(1e23 < R(math.trunc(1e23) + 1))
self.assertFalse(1e23 <= R(math.trunc(1e23) - 1))
self.assertTrue(1e23 > R(math.trunc(1e23) - 1))
self.assertFalse(1e23 >= R(math.trunc(1e23) + 1))

def testBigComplexComparisons(self):
self.assertFalse(R(10**23) == complex(10**23))
Expand Down
34 changes: 34 additions & 0 deletions Modules/mathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,39 @@ FUNC1(tan, tan,
FUNC1(tanh, tanh,
"tanh(x)\n\nReturn the hyperbolic tangent of x.")

static PyObject *
math_trunc(PyObject *self, PyObject *number)
{
static PyObject *trunc_str = NULL;
PyObject *trunc;

if (Py_TYPE(number)->tp_dict == NULL) {
if (PyType_Ready(Py_TYPE(number)) < 0)
return NULL;
}

if (trunc_str == NULL) {
trunc_str = PyUnicode_InternFromString("__trunc__");
if (trunc_str == NULL)
return NULL;
}

trunc = _PyType_Lookup(Py_TYPE(number), trunc_str);
if (trunc == NULL) {
PyErr_Format(PyExc_TypeError,
"type %.100s doesn't define __trunc__ method",
Py_TYPE(number)->tp_name);
return NULL;
}
return PyObject_CallFunctionObjArgs(trunc, number, NULL);
}

PyDoc_STRVAR(math_trunc_doc,
"trunc(x:Real) -> Integral\n"
"\n"
"Truncates x to the nearest Integral toward 0. Uses the __trunc__ magic"
"method.");

static PyObject *
math_frexp(PyObject *self, PyObject *arg)
{
Expand Down Expand Up @@ -428,6 +461,7 @@ static PyMethodDef math_methods[] = {
{"sqrt", math_sqrt, METH_O, math_sqrt_doc},
{"tan", math_tan, METH_O, math_tan_doc},
{"tanh", math_tanh, METH_O, math_tanh_doc},
{"trunc", math_trunc, METH_O, math_trunc_doc},
{NULL, NULL} /* sentinel */
};

Expand Down
13 changes: 7 additions & 6 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3616,11 +3616,11 @@ Return 0 to child process and PID of child to parent process.");
static PyObject *
posix_fork1(PyObject *self, PyObject *noargs)
{
int pid = fork1();
pid_t pid = fork1();
if (pid == -1)
return posix_error();
PyOS_AfterFork();
return PyLong_FromLong((long)pid);
return PyLong_FromLong(pid);
}
#endif

Expand All @@ -3634,12 +3634,12 @@ Return 0 to child process and PID of child to parent process.");
static PyObject *
posix_fork(PyObject *self, PyObject *noargs)
{
int pid = fork();
pid_t pid = fork();
if (pid == -1)
return posix_error();
if (pid == 0)
PyOS_AfterFork();
return PyLong_FromLong((long)pid);
return PyLong_FromLong(pid);
}
#endif

Expand Down Expand Up @@ -3741,14 +3741,15 @@ To both, return fd of newly opened pseudo-terminal.\n");
static PyObject *
posix_forkpty(PyObject *self, PyObject *noargs)
{
int master_fd = -1, pid;
int master_fd = -1;
pid_t pid;

pid = forkpty(&master_fd, NULL, NULL, NULL);
if (pid == -1)
return posix_error();
if (pid == 0)
PyOS_AfterFork();
return Py_BuildValue("(ii)", pid, master_fd);
return Py_BuildValue("(li)", pid, master_fd);
}
#endif

Expand Down
Loading

0 comments on commit 400adb0

Please sign in to comment.