Commit 5ac70430 authored by Lisa Roach's avatar Lisa Roach Committed by Raymond Hettinger

bpo-33073: Adding as_integer_ratio to ints. (GH-8750)

parent 83df50ea
......@@ -537,6 +537,14 @@ class`. In addition, it provides a few more methods:
.. versionadded:: 3.2
.. method:: int.as_integer_ratio()
Return a pair of integers whose ratio is exactly equal to the original
integer and with a positive denominator. The integer ratio of integers
(whole numbers) is always the integer as the numerator and ``1`` as the
denominator.
.. versionadded:: 3.8
Additional Methods on Float
---------------------------
......
......@@ -91,6 +91,10 @@ Other Language Changes
was lifted.
(Contributed by Serhiy Storchaka in :issue:`32489`.)
* The ``int`` type now has a new ``as_integer_ratio`` method compatible
with the existing ``float.as_integer_ratio`` method.
(Contributed by Lisa Roach in :issue:`33073`.)
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
......
......@@ -665,7 +665,7 @@ plain ol' Python and is guaranteed to be available.
True
>>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests
8
9
>>> for t in real_tests:
... print('{} {}'.format(len(t.examples), t.name))
...
......@@ -675,6 +675,7 @@ plain ol' Python and is guaranteed to be available.
2 builtins.float.hex
1 builtins.hex
1 builtins.int
3 builtins.int.as_integer_ratio
2 builtins.int.bit_length
1 builtins.oct
......
......@@ -3,6 +3,7 @@ from test import support
import sys
import enum
import random
import math
import array
......@@ -1349,6 +1350,37 @@ class LongTest(unittest.TestCase):
self.assertEqual(type(value << shift), int)
self.assertEqual(type(value >> shift), int)
def test_as_integer_ratio(self):
tests = [10, 0, -10, 1]
for value in tests:
numerator, denominator = value.as_integer_ratio()
self.assertEqual((numerator, denominator), (value, 1))
self.assertIsInstance(numerator, int)
self.assertIsInstance(denominator, int)
def test_as_integer_ratio_maxint(self):
x = sys.maxsize + 1
self.assertEqual(x.as_integer_ratio()[0], x)
def test_as_integer_ratio_bool(self):
self.assertEqual(True.as_integer_ratio(), (1, 1))
self.assertEqual(False.as_integer_ratio(), (0, 1))
self.assertEqual(type(True.as_integer_ratio()[0]), int)
self.assertEqual(type(False.as_integer_ratio()[0]), int)
def test_as_integer_ratio_int_enum(self):
class Foo(enum.IntEnum):
X = 42
self.assertEqual(Foo.X.as_integer_ratio(), (42, 1))
self.assertEqual(type(Foo.X.as_integer_ratio()[0]), int)
def test_as_integer_ratio_int_flag(self):
class Foo(enum.IntFlag):
R = 1 << 2
self.assertEqual(Foo.R.as_integer_ratio(), (4, 1))
self.assertEqual(type(Foo.R.as_integer_ratio()[0]), int)
if __name__ == "__main__":
unittest.main()
......@@ -1350,6 +1350,7 @@ Juan M. Bello Rivas
Mohd Sanad Zaki Rizvi
Davide Rizzo
Anthony Roach
Lisa Roach
Carl Robben
Ben Roberts
Mark Roberts
......
Added as_integer_ratio to ints to make them more interoperable with floats.
......@@ -118,6 +118,34 @@ int_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored))
return int_bit_length_impl(self);
}
PyDoc_STRVAR(int_as_integer_ratio__doc__,
"as_integer_ratio($self, /)\n"
"--\n"
"\n"
"Return integer ratio.\n"
"\n"
"Return a pair of integers, whose ratio is exactly equal to the original int\n"
"and with a positive denominator.\n"
"\n"
">>> (10).as_integer_ratio()\n"
"(10, 1)\n"
">>> (-10).as_integer_ratio()\n"
"(-10, 1)\n"
">>> (0).as_integer_ratio()\n"
"(0, 1)");
#define INT_AS_INTEGER_RATIO_METHODDEF \
{"as_integer_ratio", (PyCFunction)int_as_integer_ratio, METH_NOARGS, int_as_integer_ratio__doc__},
static PyObject *
int_as_integer_ratio_impl(PyObject *self);
static PyObject *
int_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored))
{
return int_as_integer_ratio_impl(self);
}
PyDoc_STRVAR(int_to_bytes__doc__,
"to_bytes($self, /, length, byteorder, *, signed=False)\n"
"--\n"
......@@ -211,4 +239,4 @@ int_from_bytes(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyOb
exit:
return return_value;
}
/*[clinic end generated code: output=fd64beb83bd16df3 input=a9049054013a1b77]*/
/*[clinic end generated code: output=6d5e92d7dc803751 input=a9049054013a1b77]*/
......@@ -5260,6 +5260,36 @@ long_is_finite(PyObject *v)
}
#endif
/*[clinic input]
int.as_integer_ratio
Return integer ratio.
Return a pair of integers, whose ratio is exactly equal to the original int
and with a positive denominator.
>>> (10).as_integer_ratio()
(10, 1)
>>> (-10).as_integer_ratio()
(-10, 1)
>>> (0).as_integer_ratio()
(0, 1)
[clinic start generated code]*/
static PyObject *
int_as_integer_ratio_impl(PyObject *self)
/*[clinic end generated code: output=e60803ae1cc8621a input=55ce3058e15de393]*/
{
if PyLong_CheckExact(self) {
return PyTuple_Pack(2, self, _PyLong_One);
} else {
PyObject *numerator = _PyLong_Copy(self);
PyObject *ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_One);
Py_DECREF(numerator);
return ratio_tuple;
}
}
/*[clinic input]
int.to_bytes
......@@ -5392,6 +5422,7 @@ static PyMethodDef long_methods[] = {
#endif
INT_TO_BYTES_METHODDEF
INT_FROM_BYTES_METHODDEF
INT_AS_INTEGER_RATIO_METHODDEF
{"__trunc__", long_long_meth, METH_NOARGS,
"Truncating an Integral returns itself."},
{"__floor__", long_long_meth, METH_NOARGS,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment