34

Not sure if the title is well put. Suggestions welcome.

Here's what I want to do. Check a condition, and then decide which function to use in a loop. For example:

if (a < 0) then
    loop_func = func1
else
    loop_func = func2
endif

I can then use loop_func as a pointer when writing my loop. Both functions take exactly the same inputs, and are different approaches on tackling the problem based on the value of a. This will allow me to only have one block of code, instead of two nearly identical blocks. This could apply to subroutines too.

Any ideas how this might be implemented?

Thank you.

Samuel Tan
  • 1,700
  • 5
  • 22
  • 35

2 Answers2

44

Yes, Fortran has procedure pointers, so you can in effect alias a function name. Here is a code example which assigns to the function pointer "f_ptr" one function or the other. Thereafter the program can use "f_ptr" and the selected function will be invoked.

module ExampleFuncs

   implicit none

contains

function f1 (x)
  real :: f1
  real, intent (in) :: x

  f1 = 2.0 * x

  return
end function f1


function f2 (x)
   real :: f2
   real, intent (in) :: x

   f2 = 3.0 * x**2

   return
end function f2

end module ExampleFuncs


program test_func_ptrs

    use ExampleFuncs
    implicit none

   abstract interface
      function func (z)
         real :: func
         real, intent (in) :: z
      end function func
   end interface

   procedure (func), pointer :: f_ptr => null ()

   real :: input

   write (*, '( / "Input test value: ")', advance="no" )
   read (*, *) input

   if ( input < 0 ) then
      f_ptr => f1
   else
      f_ptr => f2
   end if

   write (*, '(/ "evaluate function: ", ES14.4 )' )  f_ptr (input)

   stop

end program test_func_ptrs
M. S. B.
  • 28,968
  • 2
  • 46
  • 73
  • Hmm...so `=>` is some kind of assignment operator for pointers, and `procedure (func)` is some kind of declaration for procedures, like `type (mytype)` is for derived types. I'm assuming `null()` is used for initialisation and is equivalent to 0. As you can tell I'm a beginner at this. And yes, Fortran is the first programming language I'm learning properly. – Samuel Tan Dec 23 '11 at 06:13
  • A few questions. What is the `interface` for? Is that the way to specify a procedure (again, like derived type), and to ensure that what the pointer is pointing to is of the correct "type"? Also, you have a `stop` before the end of your program. Is that best practice, and should I include in my code too? – Samuel Tan Dec 23 '11 at 06:13
  • 5
    Procedure pointers are part of Fortran 2003. They have been supported by gfortran since mid-2008 -- see http://gcc.gnu.org/wiki/Fortran2003 and http://gcc.gnu.org/wiki/ProcedurePointers – M. S. B. Dec 23 '11 at 06:14
  • I used the interface to define the type of functions that f_ptr is supposed to point to -- see ftp://ftp.nag.co.uk/sc22wg5/N1551-N1600/N1579.pdf. You can also use one of the functions as a template. Yes, "=>" is the pointer assignment operator. "stop" isn't necessary. – M. S. B. Dec 23 '11 at 06:20
  • nice solution, unfortunately Fortran 2003 :) – steabert Dec 23 '11 at 07:09
  • 3
    @steabert. What's wrong with Fortran 2003? gfortran should have no problem with the procedure/interface construct, right? – Samuel Tan Dec 23 '11 at 07:28
  • 1
    @Samuel Tan: there is nothing 'wrong' with Fortran 2003, except that it's not completely supported yet by major compilers and sometimes people are limited/forced to use Fortran 77 or 90/95, so in that case the solution doesn't help. – steabert Dec 23 '11 at 08:32
  • 3
    @steabert: what are the major compilers that don't support procedure pointers? (Not gcc, pgi, cray, IBM, NAG, or intel). And who is forced to use F77/F95 in every single file in their project? – Jonathan Dursi Dec 23 '11 at 22:36
  • 1
    @JonathanDursi (1) i was referring to Fortran 2003; (2) if you're not in control of a project requiring a certain Fortran version. – steabert Dec 24 '11 at 07:30
  • 2
    @steabert: The F2003 feature under consideration is procedure pointers. Which major compiler doesn't support procedure pointers? – Jonathan Dursi Dec 24 '11 at 17:53
  • 2
    @JonathanDursi: yes you're right, but I was making a more general statement. I really don't like the fact that the standard is partly implemented, for me it makes the existence of a 'standard' rather useless, because in reality you have to go look up which feature is generally supported or not. – steabert Dec 25 '11 at 11:13
5

Most Fortran implementations do not have a standard way to manipulate function pointers or procedure pointers. However, Fortran 2003 and later have something. (See page 6 of this.)

For the given situation, this will work pretty well in its place:

 function func1 (p1, p2, etc)
 ...  as you have it already
 end

 function func2 (p1, p2, etc)
 ...  as you have it already
 end

 function funcselect (a, p1, p2, etc)
     if (a < 0) then
          x = func1 (p1, p2, etc)
     else
          x = func2 (p1, p2, etc)
     endif
 end

Then just call funcselect with the extra parameter instead of what you would have done with loop_func.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • 1
    But won't the program have to check the condition every time it calls the function? I'm trying to avoid that. – Samuel Tan Dec 23 '11 at 05:52
  • @SamuelTan: Yes, but that's hardly anything to worry about. On any modern processor, that's only a few CPU cycles: a handful of nanoseconds. – wallyk Dec 23 '11 at 05:59
  • 4
    I disagree with the statement "Fortran does not have a standard way to manipulate function pointers or procedure pointers." Procedure pointers are part of the Fortran 2003 language standard. – M. S. B. Dec 23 '11 at 06:04
  • 2
    @wallyk. In asking the question, I simplified to problem somewhat. The condition isn't actually `(a<0)`, it's a lot more complicated. And it isn't just a single simple loop that the function will be used in. To give you a picture, the function(s) will be accessed over 8 million times for 100 iterations. – Samuel Tan Dec 23 '11 at 06:58
  • @Samuel Tan: in any case, your complicated condition eventually results in two cases, so you can cast that condition to a more simple check ;) (wallyk) remove or change the sentence "Fortran does not have a standard way..." and you'll have my +1. – steabert Dec 23 '11 at 07:06
  • @steabert: How is that revised wording? – wallyk Dec 23 '11 at 07:10
  • @steabert. Why didn't I think of that? Thanks. – Samuel Tan Dec 23 '11 at 07:26
  • 3
    If you wanted to use function pointers just for optimization, it is dubious, that you would achieve any speedup in this case. I could even imagine the opposite, depending on compiler optimizations and predictability of the condition. – Vladimir F Героям слава Dec 23 '11 at 08:42
  • 3
    The OP stated that they wanted it for clarity and to avoid code duplication, both worthy goals; and using a function pointer allows them to avoid the code duplication without having the if statement deep in a loop, which is also a benefit. – Jonathan Dursi Dec 23 '11 at 22:39