Skip to content

Have fpm define precision #122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ivan-pi opened this issue Jul 16, 2020 · 4 comments
Open

Have fpm define precision #122

ivan-pi opened this issue Jul 16, 2020 · 4 comments
Labels
enhancement New feature or request

Comments

@ivan-pi
Copy link
Member

ivan-pi commented Jul 16, 2020

Recent Fortran language resources usually recommend defining a module with constants defining the precision that are later reused throughout the code, for example:

module precision
  integer, parameter :: sp = kind(1.0)
  integer, parameter :: dp = kind(1.0d0)
  integer, parameter :: wp = dp
end module

These kinds of modules are duplicated throughout libraries. This can potentially lead to incompatibilities, i.e. if library 1 uses single precision as default, and library 2 uses double precision. The user is then faced with the problem of either adapting library 1, or making library 2 use the precision module from library 1.

Would it make sense to have some mechanism to give fpm the "power" of enforcing a certain default precision? Hopefully in the long-term most Fortran programmers would default to just using constants from the stdlib precision module. This might not always be enough (i.e. interfacing with C, or perhaps using fpm on some non x86_64 architectures).

@certik
Copy link
Member

certik commented Jul 16, 2020

Great question. I don't know, I am hoping we will encourage the community to use stdlib to get precision. Fpm has the "power" to do anything, but the question is how it would work and if it makes sense. Like the promoting of single precision to double?

@ivan-pi
Copy link
Member Author

ivan-pi commented Jul 17, 2020

Yes, the entire situation is kind of messy. I have seen some codes which rely on the compiler flags such as -fdefault-real-8 to automatically upgrade real literals such as 1.0 to double precision.

In the Fortran METIS interface I used the C preprocessor:

#ifdef REAL64
    integer, parameter, public :: real_t = c_double
#else
    integer, parameter, public :: real_t = c_float
#endif

to allow users to select the precision depending on the version of METIS installed on their system.

I think it would be good if we could establish some guidelines for package developers whether such precision choices are responsibility of the package developer or the package user, and whether it should be done by 1) a preprocessor (C, fypp) + build system, or 2) the package manager.

@awvwgk awvwgk added the enhancement New feature or request label Feb 12, 2021
@ivan-pi
Copy link
Member Author

ivan-pi commented Sep 15, 2022

The Discourse Thread (https://fortran-lang.discourse.group/t/two-modules-with-the-same-name-in-one-program/4116) touched upon the issue of duplication of precision modules.

What are the existing practices for defining precision?

  1. Some libraries may provide routines in all of the precisions a compiler supports, ideally under a generic interface. An example of this is Fortran stdlib.
  2. Often legacy or user libraries provide only a single fixed precision, i.e. real(4) or real(8). This is not desirable and damages portability. The same goes for various legacy forms like real*4
  3. Some libraries (examples could be roots-fortran or the NAG Fortran library) provide a work-precision, which is potentially configurable. NAG for example provides the constants nag_rp, nag_wp, and nag_hp; the precise widths are set by the provider depending on the target platform.

For most type of numerical work, I'd argue option 3 is preferred. If one knows the code should interoperate with Python, R, MATLAB, etc. on a specific platform, the precision can also be picked accordingly. In C or C++ we can match our choice of precision with a typedef.

To achieve a level of homogeneity and composability between packages which provide reusable libraries I propose the following:

Each package provider should include in their project a module, such as

! <my_package>_precision.F90
module <my_package>_precision
implicit none

public :: wp

#ifdef __FPM__
  include "fpm/precision.inc"       ! path reserved/manipulated by fpm
  integer, parameter :: wp = fpm_wp
#else
  ! non-FPM build system, e.g. standalone Make or CMake package
  integer, parameter :: wp = kind(1.0d0)
#endif

end module <my_package>_precision

When FPM is the build system, it will pass the -D__FPM__ definition. When fpm is not the build system, package maintainers can implement whatever precision scheme/model they want. A possible example of the precision file would be:

!     precision.inc (note this file works in both fixed- and free-form)
      integer fpm_rp, fpm_wp, fpm_hp
      parameter(fpm_rp=kind(1.0e0),fpm_wp=kind(1.0d0))
      parameter(fpm_hp=selected_real_kind(33))

I imagine some package authors may prefer their own parameter names, in this case, they can over-ride them:

! <my_package>_kinds.F90
module <my_package>_kinds
! I'm one of those people who conflate storage width and precision, mind your own business!
use, intrinsic :: iso_fortran_env, only: real64

implicit none
private

public :: rk

#ifndef __FPM__
  ! real programmers use rk, wp is for quiche-eaters, 
  integer, parameter :: rk = real64
#else
  ! but since I <3 the Fortran-lang community, let's do it your way too
  include "fpm/precision.inc"
  integer, parameter :: rk => fpm_wp  
#endif

end module <my_package>_kinds
C <my_package>_precision.inc
C I'm a fixed-form person, but still like to use fpm
      include "fpm/precision.inc"
      integer wp
      parameter(wp=fpm_wp)

Further ideas/questions:

  • Instead of the include file (handy for F77 programmers), use a dedicated fpm_precision module instead. Package creators only shipping via fpm, could simply call use fpm_precision without defining their own module.
  • Select precision model via command-line flag? (e.g. based on C, IEEE, Python/NumPy, MATLAB, MKL, NAG, 4/8/16, ...)
  • Have an option in the manifest, to opt-in/out of the FPM precision override (e.g. if opt-out, then -D__FPM__ is not set)?
  • Integer/pointer precision models (lp64, ilp64,...)? See "64-bit data models" below
  • Make fpm-precision override a requirement for entry into the fpm registry? (At-least for numerical packages)
  • How to deal robustly with extended double and/or quadruple precision, given they are not mandatory for compilers?
  • Provide corresponding header with typedefs for C/C++ code? (e.g. like NAG does - https://www.nag.com/numeric/nl/nagdoc_latest/clhtml/genint/clintro.html#usingdatatypes)
  • Tools to search for incompatible precision definitions?
  • In the past, there were suggestions to use stdlib_kinds as "the" master precision module. I think it should be fpm instead. Either you join the fpm ecosystem and benefit from the homogeneous real kinds, or you keep doing your own thing and take responsibility for precision control yourself in all of your apps/packages dependencies.

See also:

@ivan-pi
Copy link
Member Author

ivan-pi commented Sep 16, 2022

If relying on the preprocessor is not desirable (although J3 opened a forum on the preprocessor - https://mailman.j3-fortran.org/pipermail/j3/2022-August/013845.html), we could rely on "standard" filenames instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants