diff options
author | Raymond Hettinger <rhettinger@users.noreply.github.com> | 2018-07-31 07:45:49 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-31 07:45:49 (GMT) |
commit | 9c18b1ae527346bc178250ad1ca07bffdacde5dd (patch) | |
tree | 117fc5de5a05d5f9da9bed73921d3ef9c02409bc /Modules/mathmodule.c | |
parent | 9d5727326af53ddd91016d98e16ae7cf829caa95 (diff) | |
download | cpython-9c18b1ae527346bc178250ad1ca07bffdacde5dd.zip cpython-9c18b1ae527346bc178250ad1ca07bffdacde5dd.tar.gz cpython-9c18b1ae527346bc178250ad1ca07bffdacde5dd.tar.bz2 |
bpo-33089: Add math.dist() for computing the Euclidean distance between two points (GH-8561)
Diffstat (limited to 'Modules/mathmodule.c')
-rw-r--r-- | Modules/mathmodule.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 726fc56..8f11f2c 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2031,6 +2031,89 @@ math_fmod_impl(PyObject *module, double x, double y) return PyFloat_FromDouble(r); } +/*[clinic input] +math.dist + + p: object(subclass_of='&PyTuple_Type') + q: object(subclass_of='&PyTuple_Type') + / + +Return the Euclidean distance between two points p and q. + +The points should be specified as tuples of coordinates. +Both tuples must be the same size. + +Roughly equivalent to: + sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q))) +[clinic start generated code]*/ + +static PyObject * +math_dist_impl(PyObject *module, PyObject *p, PyObject *q) +/*[clinic end generated code: output=56bd9538d06bbcfe input=937122eaa5f19272]*/ +{ + PyObject *item; + double *diffs; + double max = 0.0; + double csum = 0.0; + double x, px, qx, result; + Py_ssize_t i, m, n; + int found_nan = 0; + + m = PyTuple_GET_SIZE(p); + n = PyTuple_GET_SIZE(q); + if (m != n) { + PyErr_SetString(PyExc_ValueError, + "both points must have the same number of dimensions"); + return NULL; + + } + diffs = (double *) PyObject_Malloc(n * sizeof(double)); + if (diffs == NULL) { + return NULL; + } + for (i=0 ; i<n ; i++) { + item = PyTuple_GET_ITEM(p, i); + px = PyFloat_AsDouble(item); + if (px == -1.0 && PyErr_Occurred()) { + PyObject_Free(diffs); + return NULL; + } + item = PyTuple_GET_ITEM(q, i); + qx = PyFloat_AsDouble(item); + if (qx == -1.0 && PyErr_Occurred()) { + PyObject_Free(diffs); + return NULL; + } + x = fabs(px - qx); + diffs[i] = x; + found_nan |= Py_IS_NAN(x); + if (x > max) { + max = x; + } + } + if (Py_IS_INFINITY(max)) { + result = max; + goto done; + } + if (found_nan) { + result = Py_NAN; + goto done; + } + if (max == 0.0) { + result = 0.0; + goto done; + } + for (i=0 ; i<n ; i++) { + x = diffs[i] / max; + csum += x * x; + } + result = max * sqrt(csum); + + done: + PyObject_Free(diffs); + return PyFloat_FromDouble(result); +} + /* AC: cannot convert yet, waiting for *args support */ static PyObject * math_hypot(PyObject *self, PyObject *args) @@ -2358,6 +2441,7 @@ static PyMethodDef math_methods[] = { {"cos", math_cos, METH_O, math_cos_doc}, {"cosh", math_cosh, METH_O, math_cosh_doc}, MATH_DEGREES_METHODDEF + MATH_DIST_METHODDEF {"erf", math_erf, METH_O, math_erf_doc}, {"erfc", math_erfc, METH_O, math_erfc_doc}, {"exp", math_exp, METH_O, math_exp_doc}, |