summaryrefslogtreecommitdiffstats
path: root/Modules/mathmodule.c
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2018-07-31 07:45:49 (GMT)
committerGitHub <noreply@github.com>2018-07-31 07:45:49 (GMT)
commit9c18b1ae527346bc178250ad1ca07bffdacde5dd (patch)
tree117fc5de5a05d5f9da9bed73921d3ef9c02409bc /Modules/mathmodule.c
parent9d5727326af53ddd91016d98e16ae7cf829caa95 (diff)
downloadcpython-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.c84
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},