TYP04-F. Centralize kind definitions to ensure consistent precision
Programmers should define numeric kind parameters in a centralized module using standard-compliant mechanisms, such as selected_real_kind or iso_fortran_env , to ensure consistent and portable precision throughout the codebase.
In Fortran, the precision and range of intrinsic numeric types ( integer , real , complex ) are determined by their kind type parameter. Relying on default types (e.g., real ) is hazardous because their actual precision is unspecified and may vary depending on the compiler or compiler flags.
Legacy extensions, such as real*4 or real*8, are not standard and reduce code portability. Similarly, hard-coding kind values (e.g., kind=8 ) is discouraged, as compilers may interpret them differently, either as byte sizes or as sequential kind identifiers.
To ensure consistent and portable precision, developers should define numeric kinds using standard inquiry functions, such as selected_real_kind or constants provided by the iso_fortran_env module. Centralizing these definitions in a module allows changes to precision requirements to propagate throughout the codebase by modifying a single line, improving reliability and maintainability.
Noncompliant Code Example
This code mixes default real , legacy double precision , and non-standard real*8 . The precision of x and y is compiler-dependent, while z relies on a non-standard extension, reducing portability and introducing potential numerical inconsistencies.
program test_inconsistent_precision
implicit none
! Noncompliant: Default REAL depends on compiler defaults
real :: x
! Noncompliant: DOUBLE PRECISION is legacy and varies by compiler
double precision :: y
! Noncompliant: REAL*8 is a non-standard extension
real*8 :: z
x = 0.123456
y = 0.123456789012345d0
z = 1.0e0
print *, x, y, z
end program
Compliant Solution
By defining kinds centrally using selected_real_kind , this solution ensures consistent precision across the codebase and abstracts away compiler-specific defaults. Updating precision later requires modifying only the module.
module precision_mod
implicit none
public
! Compliant: sp defines 6 significant digits, range of 10^-37 to 10^37
integer, parameter :: sp = selected_real_kind(6, 37)
! Compliant: dp defines 15 significant digits, range of 10^307 to 10^307
integer, parameter :: dp = selected_real_kind(15, 307)
end module precision_mod
program test_precision
use precision_mod, only: sp, dp
implicit none
real(kind=sp) :: x
real(kind=dp) :: y
real(kind=dp) :: z
x = 0.123456_sp
y = 0.123456789012345_dp
z = 1.0_dp
print *, x, y
end program
Compliant Solution
For applications requiring specific storage sizes, iso_fortran_env provides consistent bit-width kinds (e.g., 32-bit and 64-bit reals), ensuring portability across platforms and compatibility with binary formats or C interoperability.
module precision_mod
use iso_fortran_env, only: real32, real64
implicit none
public
integer, parameter :: f32 = real32
integer, parameter :: f64 = real64
end module precision_mod
program test_precision
use precision_mod, only: f32, f64
implicit none
real(kind=f32) :: val_a
real(kind=f64) :: val_b
val_a = 1.0_f32
val_b = 1.0_f64
end program
Risk Assessment
Not centralizing and explicitly defining numeric kinds can lead to precision drift, where different components of an application use inconsistent floating-point widths. This may cause unexpected numerical results, compromise data integrity, and create portability issues across compilers or hardware platforms.
| Recommendation | Severity | Likelihood | Detectable | Repairable | Priority | Level |
| TYP04-F | High | Unlikely | Yes | No | P6 | L2 |
Bibliography
| [ Fortran 2023 Interpretation Document ] | Section 16.10.2.27 |
Attachments:
button_arrow_left.png (image/png)
button_arrow_up.png (image/png)
button_arrow_right.png (image/png)


