Skip to content

Commit f2ee21d

Browse files
bpo-39479:Add math.lcm() function: Least Common Multiple (#18547)
* Update math.rst * Update math.rst * updated whats new * Update test_math.py * Update mathmodule.c * Update mathmodule.c.h * Update ACKS * πŸ“œπŸ€– Added by blurb_it. * Update 3.9.rst * Update 2020-02-18-12-37-16.bpo-39479.j3UcCq.rst * Update math.rst * Update 2020-02-18-12-37-16.bpo-39479.j3UcCq.rst * Update test_math.py * Update ACKS * Update mathmodule.c.h * Update mathmodule.c * Update mathmodule.c.h * Update mathmodule.c.h Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent 4dee92b commit f2ee21d

File tree

7 files changed

+134
-1
lines changed

7 files changed

+134
-1
lines changed

β€ŽDoc/library/math.rst

+9
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ Number-theoretic and representation functions
136136
.. versionadded:: 3.5
137137

138138

139+
.. function:: lcm(a, b)
140+
141+
Return the least common multiple of integers *a* and *b*. The value of
142+
``lcm(a, b)`` is the smallest nonnegative integer that is a multiple of
143+
both *a* and *b*. If either *a* or *b* is zero then ``lcm(a, b)`` is zero.
144+
145+
.. versionadded:: 3.9
146+
147+
139148
.. function:: isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)
140149

141150
Return ``True`` if the values *a* and *b* are close to each other and

β€ŽDoc/whatsnew/3.9.rst

+3
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ import attempts.
216216
math
217217
----
218218

219+
Add :func:`math.lcm`: return the least common multiple of *a* and *b*.
220+
(Contributed by Ananthakrishnan in :issue:`39479`.)
221+
219222
Add :func:`math.nextafter`: return the next floating-point value after *x*
220223
towards *y*.
221224
(Contributed by Victor Stinner in :issue:`39288`.)

β€ŽLib/test/test_math.py

+35
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,41 @@ def __index__(self):
974974
with self.assertRaises(TypeError):
975975
math.isqrt(value)
976976

977+
def test_lcm(self):
978+
lcm = math.lcm
979+
self.assertEqual(lcm(0, 0), 0)
980+
self.assertEqual(lcm(1, 0), 0)
981+
self.assertEqual(lcm(-1, 0), 0)
982+
self.assertEqual(lcm(0, 1), 0)
983+
self.assertEqual(lcm(0, -1), 0)
984+
self.assertEqual(lcm(7, 1), 7)
985+
self.assertEqual(lcm(7, -1), 7)
986+
self.assertEqual(lcm(-23, 15), 345)
987+
self.assertEqual(lcm(120, 84), 840)
988+
self.assertEqual(lcm(84, -120), 840)
989+
self.assertEqual(lcm(1216342683557601535506311712,
990+
436522681849110124616458784),
991+
16592536571065866494401400422922201534178938447014944)
992+
x = 43461045657039990237
993+
y = 10645022458251153277
994+
995+
for c in (652560,
996+
57655923087165495981):
997+
a = x * c
998+
b = y * c
999+
d = x * y * c
1000+
self.assertEqual(lcm(a, b), d)
1001+
self.assertEqual(lcm(b, a), d)
1002+
self.assertEqual(lcm(-a, b), d)
1003+
self.assertEqual(lcm(b, -a), d)
1004+
self.assertEqual(lcm(a, -b), d)
1005+
self.assertEqual(lcm(-b, a), d)
1006+
self.assertEqual(lcm(-a, -b), d)
1007+
self.assertEqual(lcm(-b, -a), d)
1008+
self.assertEqual(lcm(MyIndexable(120), MyIndexable(84)), 840)
1009+
self.assertRaises(TypeError, lcm, 120.0, 84)
1010+
self.assertRaises(TypeError, lcm, 120, 84.0)
1011+
9771012
def testLdexp(self):
9781013
self.assertRaises(TypeError, math.ldexp)
9791014
self.ftest('ldexp(0,1)', math.ldexp(0,1), 0)

β€ŽMisc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Rose Ames
4545
A. Amoroso
4646
Mark Anacker
4747
Shashwat Anand
48+
Ananthakrishnan
4849
Anders Andersen
4950
Tycho Andersen
5051
John Anderson
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :func:`math.lcm` function: least common multiple.

β€ŽModules/clinic/mathmodule.c.h

+31-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€ŽModules/mathmodule.c

+54
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,59 @@ math_factorial(PyObject *module, PyObject *arg)
20172017
}
20182018

20192019

2020+
/*[clinic input]
2021+
math.lcm
2022+
x as a: object
2023+
y as b: object
2024+
/
2025+
least common multiple of x and y
2026+
[clinic start generated code]*/
2027+
2028+
static PyObject *
2029+
math_lcm_impl(PyObject *module, PyObject *a, PyObject *b)
2030+
/*[clinic end generated code: output=6f83fb6d671074ba input=efb3d7b7334b7118]*/
2031+
{
2032+
PyObject *g, *m, *f, *ab;
2033+
2034+
a = PyNumber_Index(a);
2035+
if (a == NULL) {
2036+
return NULL;
2037+
}
2038+
b = PyNumber_Index(b);
2039+
if (b == NULL) {
2040+
Py_DECREF(a);
2041+
return NULL;
2042+
}
2043+
if (_PyLong_Sign(a) == 0 || _PyLong_Sign(b) == 0) {
2044+
Py_DECREF(a);
2045+
Py_DECREF(b);
2046+
return PyLong_FromLong(0);
2047+
}
2048+
g = _PyLong_GCD(a, b);
2049+
if (g == NULL) {
2050+
Py_DECREF(a);
2051+
Py_DECREF(b);
2052+
return NULL;
2053+
}
2054+
f = PyNumber_FloorDivide(a, g);
2055+
Py_DECREF(g);
2056+
Py_DECREF(a);
2057+
if (f == NULL) {
2058+
Py_DECREF(b);
2059+
return NULL;
2060+
}
2061+
m = PyNumber_Multiply(f, b);
2062+
Py_DECREF(f);
2063+
Py_DECREF(b);
2064+
if (m == NULL) {
2065+
return NULL;
2066+
}
2067+
ab = PyNumber_Absolute(m);
2068+
Py_DECREF(m);
2069+
return ab;
2070+
}
2071+
2072+
20202073
/*[clinic input]
20212074
math.trunc
20222075
@@ -3362,6 +3415,7 @@ static PyMethodDef math_methods[] = {
33623415
MATH_ISINF_METHODDEF
33633416
MATH_ISNAN_METHODDEF
33643417
MATH_ISQRT_METHODDEF
3418+
MATH_LCM_METHODDEF
33653419
MATH_LDEXP_METHODDEF
33663420
{"lgamma", math_lgamma, METH_O, math_lgamma_doc},
33673421
MATH_LOG_METHODDEF

0 commit comments

Comments
Β (0)