1

I have a numpy program where I need to find the index of a value in array B from a sum from array A - and sadly the precission problems of numpy arrays gives me a problem with that :(

A = array([0.1,0.1,0.1,0.1,0.1])
B = array([0.1,0.2,0.3,0.4,0.5])

B==0.3
array([False, False, True, False, False], dtype=bool)

B==sum(A[:3])
array([False, False, False, False, False], dtype=bool)

B==sum(A[:2])
array([False, True, False, False, False], dtype=bool)

sum(A[:2])
0.20000000000000001

sum(A[:2])
0.30000000000000004

How can I be sure to find the value in array B that is the precise sum from array A??

Best regards Termo

3
  • 1
    For what it's worth, this is a general fact of life with floating point arithmetic. It's no different for python lists than for numpy arrays. Basically, don't test for floating point equality using ==. Commented Mar 1, 2012 at 21:24
  • 1
    Do a binary search in B with the sum of the values in B and then compare the absolute value of the difference of the value found in the B with the sum from A. You will need to two check two values in B because the sum could be slightly over or under the desired value in B. Commented Mar 1, 2012 at 21:54
  • FYI: github.com/numpy/numpy/commit/… There will be a numpy.isclose() function in 1.7. Commented Mar 4, 2012 at 22:47

1 Answer 1

1

You're just seeing the effects of floating point arithmetic. (The same thing is true if you used a python list instead of a numpy array.)

I'm actually rather surprised that there's not a built-in function to do floating point "close" comparisons in numpy... There's numpy.allclose which does it for comparing between two numpy arrays, but it just returns True or False rather than a boolean array.

Doing this in general is actually a bit tricky. inf will thrown in false positives and false negatives. Furthermore subtracting two arrays with inf or nan in them will raise a warning, so we generally want to avoid doing that...

import numpy as np

def close(a, b, rtol=1.e-5, atol=1.e-8, check_invalid=True):
    """Similar to numpy.allclose, but returns a boolean array.
    See numpy.allclose for an explanation of *rtol* and *atol*."""
    def within_tol(x, y, atol, rtol):
        return np.less_equal(np.abs(x-y), atol + rtol * np.abs(y))
    x = np.array(a, copy=False)
    y = np.array(b, copy=False)
    if not check_invalid:
        return within_tol(x, y, atol, rtol)
    xfin = np.isfinite(x)
    yfin = np.isfinite(y)
    if np.all(xfin) and np.all(yfin):
        return within_tol(x, y, atol, rtol)
    else:
        # Avoid subtraction with infinite/nan values...
        cond = np.zeros(np.broadcast(x, y).shape, dtype=np.bool)
        mask = xfin & yfin
        cond[mask] = within_tol(x[mask], y[mask], atol, rtol)
        # Inf and -Inf equality...
        cond[~mask] = (x[~mask] == y[~mask])
        # NaN equality...
        cond[np.isnan(x) & np.isnan(y)] = True
        return cond

# A few quick tests...
assert np.any(close(0.300001, np.array([0.1, 0.2, 0.3, 0.4])))

x = np.array([0.1, np.nan, np.inf, -np.inf])
y = np.array([0.1000001, np.nan, np.inf, -np.inf])
assert np.all(close(x, y))

x = np.array([0.1, 0.2, np.inf])
y = np.array([0.101, np.nan, 0.2])
assert not np.all(close(x, y))
Sign up to request clarification or add additional context in comments.

1 Comment

I don't know when it was introduced but numpy1.17 has an np.isclose() function that does return a boolean array. The docs on it are here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.