Skip to main content
GitHub

TYP03-F. Ensure intrinsic function arguments match intended precision

Programmers should use generic intrinsic procedure names and explicitly specify the kind argument for type conversion functions to prevent unintended precision loss.

While modern Fortran provides generic interfaces for most intrinsic procedures, subtle naming conventions and default behaviors can lead to silent data narrowing and numeric errors. Two common mechanisms that cause precision loss are:

  • Usage of specific (legacy) intrinsic names. Legacy Fortran required specific function names for different data types (e.g., amod for real, dmod for double precision). Using a specific name like amod with double-precision arguments forces the compiler to convert the arguments to single precision before the operation, discarding significant digits. Calling a mathematical function intended for a smaller data type results in lower-precision operations and loss of information.
  • Implicit defaults in conversion functions. In Fortran, type conversion functions (specifically cmplx , real , and int ) default to the processor-dependent default kind (usually single precision) regardless of the input precision. This differs from mathematical intrinsics (like sqrt or sin ) which automatically inherit the precision of their arguments. If a programmer passes double-precision variables to cmplx without a kind argument, the data is silently demoted to single precision.

Noncompliant Code Example

In this noncompliant example, the legacy specific intrinsic amod (intended for default real) is used on double-precision variables. The compiler demotes d_val to single precision to satisfy amod , resulting in data loss.

Non-compliant code
program specific_intrinsic
  use iso_fortran_env, only: real64
  implicit none
  real(real64) :: d_val = 1.23456789012345_real64
  real(real64) :: res

  ! Noncompliant: amod is specific to default real (single precision)
  res = amod(d_val, 2.0_real64)
  print *, res
end program

Compliant Solution

Using the generic name mod allows the compiler to select the specific procedure that matches the argument's precision.

Compliant code
prprogram generic_intrinsic
  use iso_fortran_env, only: real64
  implicit none
  real(real64) :: d_val = 1.23456789012345_real64
  real(real64) :: res

  ! Noncompliant: MOD is generic and maintains the precision of d_val
  res = mod(d_val, 2.0_real64)
  print *, res
end program

Noncompliant Code Example

In this noncompliant example, cmplx is called without a kind argument. Even though the inputs are double-precision, the result may be single-precision, leading to truncation and loss of accuracy.

Non-compliant code
program complex
  use iso_fortran_env, only: real64
  implicit none
  real(real64) :: d_real = 1.23456789012345_real64
  real(real64) :: d_imag = 9.87654321098765_real64
  complex(real64) :: z

  ! Noncompliant: CMPLX defaults to single precision
  z = cmplx(d_real, d_imag)

  print *, z
end program complex

Compliant Solution

By explicitly specifying the kind parameter, cmplx returns a double-precision complex number, preserving the precision of the inputs and preventing silent truncation.

Compliant code
program complex
  use iso_fortran_env, only: real64
  implicit none
  real(real64) :: d_real = 1.23456789012345_real64
  real(real64) :: d_imag = 9.87654321098765_real64
  complex(real64) :: z

  ! Compliant: Explicitly specify KIND to preserve double precision
  z = cmplx(d_real, d_imag, kind=real64)

  print *, z
end program complex

Risk Assessment

Implicit narrowing of function arguments can result in loss of significant digits, which may compound over subsequent calculations and produce numerically incorrect results.

RecommendationSeverityLikelihoodDetectableRepairablePriorityLevel
TYP03-FLowProbableYesYesP6L2

Bibliography

[ Fortran 2023 Interpretation Document ]Section 16.9.53 and 16.9.199

Attachments: