2

In a Fortran code, I have an array a with values ranging uniformly from 0.0 to 1.2 and I am looking for the index of the value which is closest to 1.0.

There don't seem to be any intrinsics to do this in Fortran, so I made a hacky workaround with MINLOC: (note that temp is the same shape as a)

do i=1,n
  temp(i) = 1.0 - a(i)
end do
loc = 0    !note that loc is an integer array, declared as 'loc(1)'
index_1 = minloc(abs(temp(:))) !this is the index of a closest to 1.0

This seems to do the trick.

I'm interested in other methods to achieve this, so have a few questions:

  • How does MINLOC work?
  • Are there other routines to just get straight there (i.e. without having to make a second array)?
  • How is this handled in other languages?

Thanks.


EDIT: I previously linked to this article, citing it as partial motivation to finding alternatives to MINLOC, but have removed it as some commenters have pointed out it is somewhat irrelevant. Including it seemed to be detracting from my aim which is to find alternatives to this method.

Makkasu
  • 166
  • 1
  • 1
  • 10
  • 1
    That blog post really seems to compare apples and oranges to me. The compared methods do really different things. Of course the first one is going to be fastest if it looks for an exact match and exits early. But that will not work if there might not be an exact match. – skagedal Apr 11 '15 at 23:33

2 Answers2

3

This will not run any faster than your solution, but it certainly shortens the code:

index_1 = minloc(abs(a - 1))

While you do not have to set up a temporary array yourself this way, the compiler will still do it behind the scenes. MINLOC works by brute force: there's no shortcut to finding a minimum.

If you need to search for different values repeatedly in this array, it would be much faster to first sort the array a and then perform a binary search. This will reduce the run time from O(n) to O(log(n)), where n is the size of a.

Jeff Irwin
  • 1,041
  • 8
  • 12
  • Thanks for the response, that's cleared up a few things. What do you mean by binary search? – Makkasu Apr 13 '15 at 21:48
  • 1
    [This is what I mean.](http://en.wikipedia.org/wiki/Binary_search_algorithm) Let's say you have an array [1, 2, 3, 4, 5], and you want to search for the value 5. Because the array is sorted, there is a better algorithm than just looping through all five values in the array. The binary search successively cuts the array in half, then either looks in the left half, or the right half, depending on whether the middle value is greater than or less than the value 5 that you are searching for. – Jeff Irwin Apr 13 '15 at 23:48
2

First note that the linked article does not criticize the performance of MINLOC itself, but it criticize the performance for finding a particular value.

In Fortran 2008 there is the intrinsic FINDLOC for this exact purpose, but it may not be the right thing for the problem. It would, however, be the right thing for the problem in the referenced article. See also Fortran findloc intrinsic

One reason for the slowness, which is visible immediately, is that a temporary array has to be created for abs(temp(:)) when calling MINLOC(abs(temp(:))). The other reason is that the loop in the article can exit immediately, when the match is found. That is however not important for your application.

The intrinsic MINLOC itself is probably not slow, it just searches the array in a simple loop.

These results will also differ among compilers. Did you check the performance difference for your compiler?

The final advice: just write a simple loop which avoids the temporary array.


A simple loop for finding the closest floating point element. Simple CS101 stuff.

min_diff = huge(1.0)
idx = 0

do i = 1, size(a)
  diff = abs(a(i)-to_find)
  if ( diff < min_diff) then
    idx = i
    min_diff = diff
  end if
end do
Community
  • 1
  • 1
  • Thanks for the detailed response, I had not heard of `findloc`. I haven't checked the performance for my application specifically, I was just interested in how `minloc` works and what other methods I could use. – Makkasu Apr 12 '15 at 01:38
  • 1
    @Makkasu Different compilers can implement minloc differently. You can study the GCC implementation at https://gcc.gnu.org/viewcvs/gcc/trunk/libgfortran/m4/minloc1.m4?view=markup It is actually a very simple loop, you could write it easily yourself. – Vladimir F Героям слава Apr 12 '15 at 12:42
  • @Makkasu If you care about performance, just write a very simple do loop which goes from one element to another until it finds a match, I don't really get what else you are looking for. – Vladimir F Героям слава Apr 12 '15 at 12:43
  • Firstly, that link is exactly what I was looking for, I just didn't know how to find it I guess - thanks! With regards to your second comment, sorry if I'm being dim, but the concept of detecting 'a match' when dealing with real (double precision) numbers feels a bit awkward to me - I can see how to do it for integers just fine, but for reals it doesn't feel obvious to me what the 'best' solution is. – Makkasu Apr 12 '15 at 13:13
  • If you are looking for the really closest match, you must try all elements of the array, there is no other way, of course. But it is a ver simole do loop. Do you really want me to write it down? – Vladimir F Героям слава Apr 12 '15 at 13:28
  • Yes please, I think would help. – Makkasu Apr 12 '15 at 13:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75055/discussion-between-makkasu-and-vladimir-f). – Makkasu Apr 12 '15 at 13:31