]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-39479:Add math.lcm() function: Least Common Multiple (#18547)
authorananthan-123 <ananthakrishnan15.2001@gmail.com>
Wed, 19 Feb 2020 18:21:37 +0000 (23:51 +0530)
committerGitHub <noreply@github.com>
Wed, 19 Feb 2020 18:21:37 +0000 (18:21 +0000)
* 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>
Doc/library/math.rst
Doc/whatsnew/3.9.rst
Lib/test/test_math.py
Misc/ACKS
Misc/NEWS.d/next/Library/2020-02-18-12-37-16.bpo-39479.j3UcCq.rst [new file with mode: 0644]
Modules/clinic/mathmodule.c.h
Modules/mathmodule.c

index c4c180037f8788f74a92594c05bc8024b7ad34f9..d8ac35256d1b4ba53601bcb6500c3444d589d904 100644 (file)
@@ -136,6 +136,15 @@ Number-theoretic and representation functions
    .. versionadded:: 3.5
 
 
+.. function:: lcm(a, b)
+
+   Return the least common multiple of integers *a* and *b*.  The value of
+   ``lcm(a, b)`` is the smallest nonnegative integer that is a multiple of
+   both *a* and *b*.  If either *a* or *b* is zero then ``lcm(a, b)`` is zero.
+
+   .. versionadded:: 3.9
+
+
 .. function:: isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)
 
    Return ``True`` if the values *a* and *b* are close to each other and
index 66eb9e77a7912c1e018573767d803effbef9e8fe..161675d32f670e7d6bfed1d137584b03e4159c6b 100644 (file)
@@ -216,6 +216,9 @@ import attempts.
 math
 ----
 
+Add :func:`math.lcm`: return the least common multiple of *a* and *b*.
+(Contributed by Ananthakrishnan in :issue:`39479`.)
+
 Add :func:`math.nextafter`: return the next floating-point value after *x*
 towards *y*.
 (Contributed by Victor Stinner in :issue:`39288`.)
index b3301f6a5cf74f08c5f67908b88622c99df7e217..ad8273d50cc39a935a1a5660e72e21a0d936dd69 100644 (file)
@@ -974,6 +974,41 @@ class MathTests(unittest.TestCase):
                 with self.assertRaises(TypeError):
                     math.isqrt(value)
 
+    def test_lcm(self):
+        lcm = math.lcm
+        self.assertEqual(lcm(0, 0), 0)
+        self.assertEqual(lcm(1, 0), 0)
+        self.assertEqual(lcm(-1, 0), 0)
+        self.assertEqual(lcm(0, 1), 0)
+        self.assertEqual(lcm(0, -1), 0)
+        self.assertEqual(lcm(7, 1), 7)
+        self.assertEqual(lcm(7, -1), 7)
+        self.assertEqual(lcm(-23, 15), 345)
+        self.assertEqual(lcm(120, 84), 840)
+        self.assertEqual(lcm(84, -120), 840)
+        self.assertEqual(lcm(1216342683557601535506311712,
+                             436522681849110124616458784),
+                             16592536571065866494401400422922201534178938447014944)
+        x = 43461045657039990237
+        y = 10645022458251153277
+
+        for c in (652560,
+                  57655923087165495981):
+            a = x * c
+            b = y * c
+            d = x * y * c
+            self.assertEqual(lcm(a, b), d)
+            self.assertEqual(lcm(b, a), d)
+            self.assertEqual(lcm(-a, b), d)
+            self.assertEqual(lcm(b, -a), d)
+            self.assertEqual(lcm(a, -b), d)
+            self.assertEqual(lcm(-b, a), d)
+            self.assertEqual(lcm(-a, -b), d)
+            self.assertEqual(lcm(-b, -a), d)
+        self.assertEqual(lcm(MyIndexable(120), MyIndexable(84)), 840)
+        self.assertRaises(TypeError, lcm, 120.0, 84)
+        self.assertRaises(TypeError, lcm, 120, 84.0)
+
     def testLdexp(self):
         self.assertRaises(TypeError, math.ldexp)
         self.ftest('ldexp(0,1)', math.ldexp(0,1), 0)
index e8ce30310bfd8e9b4f8e445d218db48fc11d14cf..b11ee9cdea67d79e9932ada9973326127e7bb9df 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -45,6 +45,7 @@ Rose Ames
 A. Amoroso
 Mark Anacker
 Shashwat Anand
+Ananthakrishnan
 Anders Andersen
 Tycho Andersen
 John Anderson
diff --git a/Misc/NEWS.d/next/Library/2020-02-18-12-37-16.bpo-39479.j3UcCq.rst b/Misc/NEWS.d/next/Library/2020-02-18-12-37-16.bpo-39479.j3UcCq.rst
new file mode 100644 (file)
index 0000000..6f16623
--- /dev/null
@@ -0,0 +1 @@
+Add :func:`math.lcm` function: least common multiple.
index f95d291d41f8046d2e927a9531918bd5a7be9f21..df45a1a0c5e855abb168810096d1797c2e45e4d4 100644 (file)
@@ -85,6 +85,36 @@ PyDoc_STRVAR(math_factorial__doc__,
 #define MATH_FACTORIAL_METHODDEF    \
     {"factorial", (PyCFunction)math_factorial, METH_O, math_factorial__doc__},
 
+PyDoc_STRVAR(math_lcm__doc__,
+"lcm($module, x, y, /)\n"
+"--\n"
+"\n"
+"least common multiple of x and y");
+
+#define MATH_LCM_METHODDEF    \
+    {"lcm", (PyCFunction)(void(*)(void))math_lcm, METH_FASTCALL, math_lcm__doc__},
+
+static PyObject *
+math_lcm_impl(PyObject *module, PyObject *a, PyObject *b);
+
+static PyObject *
+math_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+    PyObject *return_value = NULL;
+    PyObject *a;
+    PyObject *b;
+
+    if (!_PyArg_CheckPositional("lcm", nargs, 2, 2)) {
+        goto exit;
+    }
+    a = args[0];
+    b = args[1];
+    return_value = math_lcm_impl(module, a, b);
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(math_trunc__doc__,
 "trunc($module, x, /)\n"
 "--\n"
@@ -895,4 +925,4 @@ math_ulp(PyObject *module, PyObject *arg)
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=9b51d215dbcac060 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=f8daa185c043a7b7 input=a9049054013a1b77]*/
index 309f229159540125166be069ecefc3fa5a088eec..f74b7e1a34203b5d707c98fcd8b0da9a4cc0413d 100644 (file)
@@ -2017,6 +2017,59 @@ math_factorial(PyObject *module, PyObject *arg)
 }
 
 
+/*[clinic input]
+math.lcm
+    x as a: object
+    y as b: object
+    /
+least common multiple of x and y
+[clinic start generated code]*/
+
+static PyObject *
+math_lcm_impl(PyObject *module, PyObject *a, PyObject *b)
+/*[clinic end generated code: output=6f83fb6d671074ba input=efb3d7b7334b7118]*/
+{
+    PyObject *g, *m, *f, *ab;
+
+    a = PyNumber_Index(a);
+    if (a == NULL) {
+        return NULL;
+    }
+    b = PyNumber_Index(b);
+    if (b == NULL) {
+        Py_DECREF(a);
+        return NULL;
+    }
+    if (_PyLong_Sign(a) == 0 || _PyLong_Sign(b) == 0) {
+        Py_DECREF(a);
+        Py_DECREF(b);
+        return PyLong_FromLong(0);
+    }
+    g = _PyLong_GCD(a, b);
+    if (g == NULL) {
+        Py_DECREF(a);
+        Py_DECREF(b);
+        return NULL;
+    }
+    f = PyNumber_FloorDivide(a, g);
+    Py_DECREF(g);
+    Py_DECREF(a);
+    if (f == NULL) {
+        Py_DECREF(b);
+        return NULL;
+    }
+    m = PyNumber_Multiply(f, b);
+    Py_DECREF(f);
+    Py_DECREF(b);
+    if (m == NULL) {
+        return NULL;
+    }
+    ab = PyNumber_Absolute(m);
+    Py_DECREF(m);
+    return ab;
+}
+
+
 /*[clinic input]
 math.trunc
 
@@ -3362,6 +3415,7 @@ static PyMethodDef math_methods[] = {
     MATH_ISINF_METHODDEF
     MATH_ISNAN_METHODDEF
     MATH_ISQRT_METHODDEF
+    MATH_LCM_METHODDEF
     MATH_LDEXP_METHODDEF
     {"lgamma",          math_lgamma,    METH_O,         math_lgamma_doc},
     MATH_LOG_METHODDEF