I have just noticed that the accepted answer doesn't work. E.g. this case:
a = 1-np.random.random(20)*0.05
<20 uniformly chosen values between 0.95 and 1.0>
np.sort(a)
>>>> array([ 0.9514548 , 0.95172218, 0.95454535, 0.95482343, 0.95599525,
0.95997008, 0.96385762, 0.96679186, 0.96873524, 0.97016127,
0.97377579, 0.98407259, 0.98490461, 0.98964753, 0.9896733 ,
0.99199411, 0.99261766, 0.99317258, 0.99420183, 0.99730928])
TOL = 0.01
Results into:
a.flat[i[d>TOL]]
>>>> array([], dtype=float64)
Simply because none of the values of the sorted input array are sufficiently spaced to be at least “TOL“ appart, while the correct result should be:
>>>> array([ 0.9514548, 0.96385762, 0.97016127, 0.98407259,
0.99199411])
(although it depends how you decide which value to take within the “TOL“)
You should use the fact that integers don't suffer from such machine precision effect:
np.unique(np.floor(a/TOL).astype(int))*TOL
>>>> array([ 0.95, 0.96, 0.97, 0.98, 0.99])
which performs 5 times faster than the proposed solution (according to %timeit).
Note that “.astype(int)“ is optional, although removing it deteriorates the performance by a factor of 1.5, given that extracting uniques out of an array of int is much faster.
You might want to add half the “TOL“ to the results of uniques, to compensate for the flooring effect:
(np.unique(np.floor(a/TOL).astype(int))+0.5)*TOL
>>>> array([ 0.955, 0.965, 0.975, 0.985, 0.995])