From 533eb93aed5e42b29041bbbfadc5cd57745757fc Mon Sep 17 00:00:00 2001 From: Warren Weckesser Date: Thu, 14 May 2020 14:03:05 -0400 Subject: DOC: Warn about behavior of ptp with signed integers. * Add a warning to the docstrings of numpy.ma.MaskedArray.ptp and numpy.ptp about a problem with signed integer arrays. * Add an example to the the docstring of numpy.ptp that demonstrates the issue and suggests a work-around. * Add an "Examples" section to the docstring of MaskedArray.ptp which includes the new example added to the docstring of numpy.ptp. * Make the numbers in the basic example more interesting. --- numpy/core/fromnumeric.py | 39 ++++++++++++++++++++++++++++++++------- numpy/ma/core.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index b32ad8d35..285b75314 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -2494,6 +2494,14 @@ def ptp(a, axis=None, out=None, keepdims=np._NoValue): The name of the function comes from the acronym for 'peak to peak'. + .. warning:: + `ptp` preserves the data type of the array. This means the + return value for an input of signed integers with n bits + (e.g. `np.int8`, `np.int16`, etc) is also a signed integer + with n bits. In that case, peak-to-peak values greater than + ``2**(n-1)-1`` will be returned as negative values. An example + with a work-around is shown below. + Parameters ---------- a : array_like @@ -2531,16 +2539,33 @@ def ptp(a, axis=None, out=None, keepdims=np._NoValue): Examples -------- - >>> x = np.arange(4).reshape((2,2)) - >>> x - array([[0, 1], - [2, 3]]) + >>> x = np.array([[4, 9, 2, 10], + ... [6, 9, 7, 12]]) + + >>> np.ptp(x, axis=1) + array([8, 6]) >>> np.ptp(x, axis=0) - array([2, 2]) + array([2, 0, 5, 2]) - >>> np.ptp(x, axis=1) - array([1, 1]) + >>> np.ptp(x) + 10 + + This example shows that a negative value can be returned when + the input is an array of signed integers. + + >>> y = np.array([[1, 127], + ... [0, 127], + ... [-1, 127], + ... [-2, 127]], dtype=np.int8) + >>> np.ptp(y, axis=1) + array([ 126, 127, -128, -127], dtype=int8) + + A work-around is to use the `view()` method to view the result as + unsigned integers with the same bit width: + + >>> np.ptp(y, axis=1).view(np.uint8) + array([126, 127, 128, 129], dtype=uint8) """ kwargs = {} diff --git a/numpy/ma/core.py b/numpy/ma/core.py index a7214f9bf..f575113e2 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -5860,6 +5860,14 @@ class MaskedArray(ndarray): Return (maximum - minimum) along the given dimension (i.e. peak-to-peak value). + .. warning:: + `ptp` preserves the data type of the array. This means the + return value for an input of signed integers with n bits + (e.g. `np.int8`, `np.int16`, etc) is also a signed integer + with n bits. In that case, peak-to-peak values greater than + ``2**(n-1)-1`` will be returned as negative values. An example + with a work-around is shown below. + Parameters ---------- axis : {None, int}, optional @@ -5882,6 +5890,45 @@ class MaskedArray(ndarray): A new array holding the result, unless ``out`` was specified, in which case a reference to ``out`` is returned. + Examples + -------- + >>> x = np.ma.MaskedArray([[4, 9, 2, 10], + ... [6, 9, 7, 12]]) + + >>> x.ptp(axis=1) + masked_array(data=[8, 6], + mask=False, + fill_value=999999) + + >>> x.ptp(axis=0) + masked_array(data=[2, 0, 5, 2], + mask=False, + fill_value=999999) + + >>> x.ptp() + 10 + + This example shows that a negative value can be returned when + the input is an array of signed integers. + + >>> y = np.ma.MaskedArray([[1, 127], + ... [0, 127], + ... [-1, 127], + ... [-2, 127]], dtype=np.int8) + >>> y.ptp(axis=1) + masked_array(data=[ 126, 127, -128, -127], + mask=False, + fill_value=999999, + dtype=int8) + + A work-around is to use the `view()` method to view the result as + unsigned integers with the same bit width: + + >>> y.ptp(axis=1).view(np.uint8) + masked_array(data=[126, 127, 128, 129], + mask=False, + fill_value=999999, + dtype=uint8) """ if out is None: result = self.max(axis=axis, fill_value=fill_value, -- cgit v1.2.1