Using 'find' for finding whole numbers

13 次查看(过去 30 天)
Roisin Loughnane
Roisin Loughnane 2017-10-16
评论: dpb 2017-10-17
Hello,
I have a large matrix containing latitude gird edges (lat_grid) and I wish to find lat values from a vector (lat) using the find function. I use this command:
R = find(lat_grid <= lat,1,'first');
This works fine for floating numbers, but does work for whole numbers, which are numerous in the grid matrix (lat_grid).
How can I either convert the whole numbers to floating points with two decimal places?
OR how do I fix the find command to include finding the nearest whole numbers?
  4 个评论
per isakson
per isakson 2017-10-16
Cleve's piece is dated 1996 and I guess "flint" always been a part of Matlab. I think Cleve's piece is good background reading and it is relevant to comparison of floating point numbers. (I replace "called" by "they call" in my comment above.)
dpb
dpb 2017-10-16
There's the key...and could be OPs issue if he were looking for a specific integer value -- but his test is for
R = find(lat_grid <= lat,1,'first');
which is an inequality, not an exact match so the FP rounding issue in comparisons internal to FIND won't be a factor unless his lat value were to be within eps of the value in question that was trying to be located or less than, in this case, any integer in the array being searched.
As Cleve says, integers in floating point are exact representations as long as their precision is within the length of the (53) bits available in the double mantissa but OP isn't searching for exact match anyway.
There's something else going on we don't have sufficient data to discern the problem as yet...

请先登录,再进行评论。

回答(2 个)

dpb
dpb 2017-10-16
编辑:dpb 2017-10-17
find has no difficulty in returning integer-valued floating-point numbers (which is the default storage in Matlab and in an array all values are of the same type). Consequently, your issue is likely that the "integers" actually aren't quite actually integer-valued but were computed from floating point values and therefore have some rounding and are only displayed to precision such that they appear to be whole numbers.
There is a function specifically designed for such purpose ismembertol will find values within a tolerance of given value(s); that's probably what you want.
If this doesn't answer the ?, post a (small) dataset that illustrates the problem.
ADDENDUM
If you're going to traverse the route S Lord has shown with later revision than I have here, I'll withdraw from the playing field, but I'll note a few things from your additional input you've provided as general comments...
The sequence you wrote:
>> lonW = 0; %easterly limit
lonE = 360; %westerly limit
res = 0.25;
n_lon = (lonE - lonW)/res; %no. longitude boxes
for n = (1:n_lon)
lon_grid(n) = lonW + (n-1)*res;
end
>>
is quite inefficient...use something like
>> long=linspace(0,360-res,n_lon); % use builtin function rather than loop
>> all(long==lon_grid) % get same answer??? (Yes-->1)
ans =
1
>>
NB: The last entry in the lon_grid array is NOT 360 if that's the intent; it's one element short; hence the "-res" in the argument list.
Alternatively, there's colon that may be a little more handy given the delta instead of length...
>> long=[0:res:360-res]; % colon
>> all(long==lon_grid) % also builds identical vector
ans =
1
>>
Now the question is, do we, or do we not have integer-valued degrees or was there roundoff in generating the values???
>> sum(lon_grid==fix(lon_grid)) % how many are integer-valued?
ans =
360
>>
So indeed, there are 360 integers in the vector as we hoped, 0:359 (360 isn't in the array, remember? :) )
>> lon_grid(end) % last element is one short of 360...intended?????
ans =
359.7500
>>
Now back to your original question--
>> lat=89.15;
>> find(lon_grid<=lat,1,'last')
ans =
357
>> lon_grid(ans)
ans =
89
>>
So the logic DOES work if the inputs are as expected -- hence, the supposition earlier that there's something else going on in the actual case that isn't represented in the question and supporting data.
More than likely, lat isn't what you think it is or you've made some other coding error so the values just aren't what you really think they are at the time you see the failure -- as noted earlier, set a breakpoint to see what's going on in the actual application because the symptom isn't owing to the cause you think; the function works as expected if the data are what are here.
Now, this isn't to say that the newer functions might not be a better implementation of the problem; just that what problem you're having at present is not owing to find and integer/non-integer values; it's that you really have some other values than you think at the moment of the failure.
  7 个评论
Steven Lord
Steven Lord 2017-10-17
discretize can't handle a case like this:
discretize(5, [1 2 3 6 4 4.5])
The fourth bin would be [6, 4) but that doesn't make sense as a bin. Give me a number that is greater than or equal to 6 and less than 4 simultaneously.
You can make your edges non-decreasing and ask discretize to return the non-decreasing edges.
[n, edges] = discretize(5, sort([1 2 3 6 4 4.5]))
dpb
dpb 2017-10-17
One last comment...the find solution works as you wrote it iff the searched-for value is greater than that wanted in absolute value -- this works for the vector 0:360 as all are positive values but it will NOT work reliably for the case of the latitude vector of -90:90 because the sign change switches the needed direction of the search.
Before the new-fangled discretize, one way to do this would have been histc returning the optional bin, another way that works irrespective of the sign is
>> interp1(lon_grid,1:length(lon_grid),fix(lon),'previous')
ans =
885
893
893
893
893
901
901
905
925
993
997
997
997
1001
1001
1001
1001
1001
1017
1033
>> lon_grid(ans)
ans =
Columns 1 through 17
221 223 223 223 223 225 225 226 231 248 249 249 249 250 250 250 250
Columns 18 through 20
250 254 258
>>
for the example vector you give above. The above is just an inverse lookup for the position in the array and is equivalent to
find(lon_grid==fix(lon))
excepting is "vectorizable" if that's a need; find isn't directly.

请先登录,再进行评论。


Guillaume
Guillaume 2017-10-16
I use this command R = find(lat_grid <= lat,1,'first'). This works fine for floating numbers
No, it doesn't work. If it has worked so far, you've been lucky. It wouldn't be hard to find an example where this would break, i.e. where the true value stored in memory is just slightly above (or below) your search value.
The proper way of finding any value in an array of numbers which can be floating point is to do a comparison of the difference to a tolerance (or use ismembertol as has been suggested):
tol = 1e-6; %whatever is appropriate for the magnitude of your numbers
R = find(abs(lat_grid - lat) <= tol);
Your method will break. It may not have failed yet but it will.
  1 个评论
dpb
dpb 2017-10-17
Again, that's true if he were searching for an exact match on a FP, non-integer value. But, as demonstrated above, his data do contain the integer degree values (unless he's somehow inadvertently modified them which could be a problem, granted) so the test will work as intended.

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Loops and Conditional Statements 的更多信息

标签

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by