j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
177 stars 15 forks source link

new intrinsic `absq()` function for computing squared-absolute value of complex, real, and integer values #312

Open shahmoradi opened 1 year ago

shahmoradi commented 1 year ago

A frequent type-agnostic calculation is abs(x)**2 where x is complex or real (or integer). While the above expression is generic, it involves a costly but, more importantly, unnecessary square-root operation for values of type complex. The current community solution is to define a preprocessor macro that properly and efficiently computes the result for arguments of various types. This can be avoided by adding a new intrinsic function absq(x) that returns,

  1. x**2 if x is real or integer.
  2. x%re**2 + x%im**2 if x is complex.
klausler commented 1 year ago

Why would this need to be intrinsic? Can't you define this as an elemental generic?

shahmoradi commented 1 year ago

We could ask the same question about other existing intrinsics, like abs(), cosd(), sind().
Indeed, I have been using FPP macros for cosd(), sind(). I see multiple paths forward:

  1. generic user-defined function: Assuming five kinds for the three intrinsic types, I'd have to write 15 separate functions for absq() to achieve such simple generic functionality. In my current use case, the function has to be called inside a triply-nested loop. I am not ready yet to endure such pain and potential performance impact. So, instead, I have been using FPP macros to handle this usage gracefully.
  2. generic user-defined template function. Possibly a good solution. I look forward to using it in the next 5-10 years.
  3. generic user-defined standardized macros. The standard committee does not appear to like this idea at all.
  4. non-portable existing FPP macros. This is what I am using frequently. But at some point, one gets frustrated with so many non-standard macro definitions here and there and the difficulty of performing such simple tasks generically and efficiently without FPP.
  5. Hence, this proposal to add this functionality to the standard, which could be done in several ways like,
    1. through a new intrinsic absq().
    2. through extending dot_product() interface to scalar (single) arguments (to signify dot product with self).

For now, I am stuck with option 4.

milancurcic commented 1 year ago

Would this be a good fit for stdlib?

klausler commented 1 year ago
  1. generic user-defined template function. Possibly a good solution. I look forward to using it in the next 5-10 years.

F'2023 is done. You won't get anything new, including your absq, into a Fortran standard, until F'202Y, where Y is at least 8, or into a Fortran compiler until a few years after that. So by the time you get absq, assuming that you can get it into a Fortran standard, you'll also have the generic user-defined template functions and you won't need a standard absq. (Assuming that the template feature is capable of implementing absq, that is.)

shahmoradi commented 1 year ago

It would be an excellent addition to stdlib if we ensure the compilers inline all usage. I hoped this would be the case, but I have noticed performance degradations using (a similar functionality to) stdlib optval(). I need to find and rerun the benchmarks to quantify the impact here.

Alternatively, could stdlib define an FPP include (header) file with macros for such frequently used functionalities? I am unsure whether all available compilers follow the same FPP conventions to allow defining such an FPP include file. Intel and GNU FPP overlap significantly (though incompletely), but I do not know about the others.

certik commented 1 year ago

Why cannot a compiler optimizer automatically optimize abs(x)**2?