diff options
author | Tal Einat <taleinat@gmail.com> | 2015-05-31 22:05:00 +0300 |
---|---|---|
committer | Tal Einat <taleinat@gmail.com> | 2015-05-31 22:05:00 +0300 |
commit | d5519ed7f4889060363673ec802177250299920e (patch) | |
tree | 90bf7cc72a340c9512bcf7b4d0837ac845347c6a /Modules/cmathmodule.c | |
parent | 439c5fe3ae62741f01da7e78a9c198375e837857 (diff) | |
download | cpython-git-d5519ed7f4889060363673ec802177250299920e.tar.gz |
Issue #19543: Implementation of isclose as per PEP 485
For details, see:
PEP 0485 -- A Function for testing approximate equality
Functions added: math.isclose() and cmath.isclose().
Original code by Chris Barker. Patch by Tal Einat.
Diffstat (limited to 'Modules/cmathmodule.c')
-rw-r--r-- | Modules/cmathmodule.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 921eaaa88a..d12e4c50cd 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1114,6 +1114,73 @@ cmath_isinf_impl(PyModuleDef *module, Py_complex z) Py_IS_INFINITY(z.imag)); } +/*[clinic input] +cmath.isclose -> bool + + a: Py_complex + b: Py_complex + * + rel_tol: double = 1e-09 + maximum difference for being considered "close", relative to the + magnitude of the input values + abs_tol: double = 0.0 + maximum difference for being considered "close", regardless of the + magnitude of the input values + +Determine whether two complex numbers are close in value. + +Return True if a is close in value to b, and False otherwise. + +For the values to be considered close, the difference between them must be +smaller than at least one of the tolerances. + +-inf, inf and NaN behave similarly to the IEEE 754 Standard. That is, NaN is +not close to anything, even itself. inf and -inf are only close to themselves. +[clinic start generated code]*/ + +static int +cmath_isclose_impl(PyModuleDef *module, Py_complex a, Py_complex b, + double rel_tol, double abs_tol) +/*[clinic end generated code: output=da0c535fb54e2310 input=df9636d7de1d4ac3]*/ +{ + double diff; + + /* sanity check on the inputs */ + if (rel_tol < 0.0 || abs_tol < 0.0 ) { + PyErr_SetString(PyExc_ValueError, + "tolerances must be non-negative"); + return -1; + } + + if ( (a.real == b.real) && (a.imag == b.imag) ) { + /* short circuit exact equality -- needed to catch two infinities of + the same sign. And perhaps speeds things up a bit sometimes. + */ + return 1; + } + + /* This catches the case of two infinities of opposite sign, or + one infinity and one finite number. Two infinities of opposite + sign would otherwise have an infinite relative tolerance. + Two infinities of the same sign are caught by the equality check + above. + */ + + if (Py_IS_INFINITY(a.real) || Py_IS_INFINITY(a.imag) || + Py_IS_INFINITY(b.real) || Py_IS_INFINITY(b.imag)) { + return 0; + } + + /* now do the regular computation + this is essentially the "weak" test from the Boost library + */ + + diff = _Py_c_abs(_Py_c_diff(a, b)); + + return (((diff <= rel_tol * _Py_c_abs(b)) || + (diff <= rel_tol * _Py_c_abs(a))) || + (diff <= abs_tol)); +} PyDoc_STRVAR(module_doc, "This module is always available. It provides access to mathematical\n" @@ -1129,6 +1196,7 @@ static PyMethodDef cmath_methods[] = { CMATH_COS_METHODDEF CMATH_COSH_METHODDEF CMATH_EXP_METHODDEF + CMATH_ISCLOSE_METHODDEF CMATH_ISFINITE_METHODDEF CMATH_ISINF_METHODDEF CMATH_ISNAN_METHODDEF |