2

I want to find a float in a arry like this:

arr = np.asarray([1351.1 , 1351.11, 1351.14, 1351.16, 1351.17])
index = np.searchsorted(arr, 1351.14, side="right") - 1 # return 2

But I find that it return wrong like this:

index = np.searchsorted(arr, 1351.1 + 0.04, side="right") - 1 # return 1

Because I want to search value like this:

indexes = np.searchsorted(arr, arr[0] + np.arange(10) * 0.01, side="right") - 1  # this will be wrong because of the problem above
roger
  • 9,063
  • 20
  • 72
  • 119
  • Have you considered searching for the *closest* value to the target (e.g., by using `searchsorted` on the array `0.5 * (arr[1:] + arr[:-1])` of midpoints of `arr`)? – Mark Dickinson Jan 26 '21 at 16:04
  • @MarkDickinson as you see, at last I want to search `np.searchsorted(arr, arr[0] + np.arange(10) * 0.01, side="right") - 1`, maybe your solution a little bit comple – roger Jan 27 '21 at 01:28

2 Answers2

0

Pretty sure this is due to the representation error.

In my attempts, as 1351.14 * 10000 == 13511400.000000002 and (1351.1 + 0.04) * 10000 == 13511399.999999998, 1351.14 != 1351.1 + 0.04. You can see some extra information on this in Python in this stackoverflow question.

For a quick fix I tried to replace 1351.1 + 0.04 with round(1351.1 + 0.04, 2) and it seem to work (return 2), although I am not sure this is the best method.

dm2
  • 4,053
  • 3
  • 17
  • 28
  • 1
    `round` won't work consistently unless you apply it to both the numbers in the array and the number you're searching. – Mark Ransom Jan 26 '21 at 15:33
0

As @dm2 suggested, forcing the precision on the second expression can be a solution. Forcing the values to float32 seems to work. But I ask someone with a better understanding of arithmetic operations in numpy to give a detailed answer.

import numpy as np

arr = np.asarray([1351.1 , 1351.11, 1351.14, 1351.16, 1351.17],dtype=np.float32)
index = np.searchsorted(arr, np.float32(1351.1 + 0.04), side="right") - 1 
print(index)
Vasco Ludovico
  • 141
  • 1
  • 5
  • are you sure? you result is still `1`, it should be `2` – roger Jan 26 '21 at 15:05
  • You are right, my bad. I'll edit the answer then. What happened is that I had force it to float32 and assumed it would work with float64. I still think someone with a better knowledge of numpy arithmetic operations should help us here. – Vasco Ludovico Jan 26 '21 at 15:20