| 1 | MODULE numerics |
|---|
| 2 | !----------------------------------------------------------------------- |
|---|
| 3 | ! NAME |
|---|
| 4 | ! numerics |
|---|
| 5 | ! |
|---|
| 6 | ! DESCRIPTION |
|---|
| 7 | ! Management of numerical precision and special values (NaN and Inf) |
|---|
| 8 | ! throughout the code. |
|---|
| 9 | ! |
|---|
| 10 | ! AUTHORS & DATE |
|---|
| 11 | ! JB Clement, 01/2026 |
|---|
| 12 | ! |
|---|
| 13 | ! NOTES |
|---|
| 14 | ! The intrinsic function storage_size() returns the storage size of |
|---|
| 15 | ! argument in bits. |
|---|
| 16 | !----------------------------------------------------------------------- |
|---|
| 17 | |
|---|
| 18 | ! DEPENDENCIES |
|---|
| 19 | ! ------------ |
|---|
| 20 | use, intrinsic :: iso_fortran_env, only : int8, int16, int32, int64, real32, real64, real128 |
|---|
| 21 | !~ use, intrinsic :: ieee_arithmetic |
|---|
| 22 | |
|---|
| 23 | ! DECLARATION |
|---|
| 24 | ! ----------- |
|---|
| 25 | implicit none |
|---|
| 26 | |
|---|
| 27 | ! PARAMETERS |
|---|
| 28 | ! ---------- |
|---|
| 29 | ! Integers |
|---|
| 30 | integer, parameter :: lli_candidate = selected_int_kind(38) |
|---|
| 31 | logical, parameter :: has_int128 = (lli_candidate > 0) |
|---|
| 32 | integer, parameter :: ti = int8 ! Tiny integer = 8 bits |
|---|
| 33 | integer, parameter :: si = int16 ! Short integer = 16 bits |
|---|
| 34 | integer, parameter :: di = int32 ! Standard integer = 32 bits (default) |
|---|
| 35 | integer, parameter :: li = int64 ! Long integer = 64 bits |
|---|
| 36 | integer, parameter :: lli = merge(lli_candidate,li,has_int128) ! Long long integer = 128 bits (if available, otherwise fallback to int64) |
|---|
| 37 | integer, parameter :: wi = di ! Working integer |
|---|
| 38 | |
|---|
| 39 | ! Reals |
|---|
| 40 | integer, parameter :: sp = real32 ! Simple precision = 32 bits = 1-bit sign + 8-bit exponent + 23-bit significand |
|---|
| 41 | integer, parameter :: dp = real64 ! Double precision = 64 bits = 1-bit sign + 11-bit exponent + 52-bit significand |
|---|
| 42 | integer, parameter :: qp = real128 ! Quadruple precision = 128 bits = 1-bit sign + 15-bit exponent + 112-bit significand |
|---|
| 43 | integer, parameter :: wp = dp ! Working precision |
|---|
| 44 | |
|---|
| 45 | ! Logicals |
|---|
| 46 | ! The precision is given by the compiler to be the same as the standard integer precision (32 bits) for memory reasons. |
|---|
| 47 | ! It can be interesting to have smaller logical to reduce memory load. |
|---|
| 48 | ! But be careful: definition is compiler-dependent and processor-dependent! So the following kinds are not guaranteed for logicals! |
|---|
| 49 | integer, parameter :: k1 = 1 ! kind = 1 should be 8 bits |
|---|
| 50 | integer, parameter :: k2 = 2 ! kind = 2 should be 16 bits |
|---|
| 51 | integer, parameter :: k4 = 4 ! kind = 4 should be 32 bits (default) |
|---|
| 52 | |
|---|
| 53 | ! Smallest strictly positive representable real number |
|---|
| 54 | real(sp), parameter :: smallest_sp = tiny(1._sp) |
|---|
| 55 | real(dp), parameter :: smallest_dp = tiny(1._dp) |
|---|
| 56 | real(qp), parameter :: smallest_qp = tiny(1._qp) |
|---|
| 57 | real(wp), parameter :: smallest_nb = tiny(1._wp) |
|---|
| 58 | |
|---|
| 59 | ! Largest representable number |
|---|
| 60 | integer(ti), parameter :: largest_ti = huge(1_ti) |
|---|
| 61 | integer(si), parameter :: largest_si = huge(1_si) |
|---|
| 62 | integer(di), parameter :: largest_di = huge(1_di) |
|---|
| 63 | integer(li), parameter :: largest_li = huge(1_li) |
|---|
| 64 | integer(lli), parameter :: largest_lli = huge(1_lli) |
|---|
| 65 | integer(wi), parameter :: largest_wi = huge(1_wi) |
|---|
| 66 | real(sp), parameter :: largest_sp = huge(1._sp) |
|---|
| 67 | real(dp), parameter :: largest_dp = huge(1._dp) |
|---|
| 68 | real(qp), parameter :: largest_qp = huge(1._qp) |
|---|
| 69 | real(wp), parameter :: largest_nb = huge(1._wp) |
|---|
| 70 | |
|---|
| 71 | ! Machine epsilon: smallest positive real number such that 1 + epsilon > 1 |
|---|
| 72 | real(sp), parameter :: minieps_sp = epsilon(1._sp) |
|---|
| 73 | real(dp), parameter :: minieps_dp = epsilon(1._dp) |
|---|
| 74 | real(qp), parameter :: minieps_qp = epsilon(1._qp) |
|---|
| 75 | real(wp), parameter :: minieps = epsilon(1._wp) |
|---|
| 76 | real(wp), parameter :: tol = 100._wp*minieps |
|---|
| 77 | |
|---|
| 78 | ! Minimum number of significant decimal digits |
|---|
| 79 | integer, parameter :: prec_sp = precision(1._sp) |
|---|
| 80 | integer, parameter :: prec_dp = precision(1._dp) |
|---|
| 81 | integer, parameter :: prec_qp = precision(1._qp) |
|---|
| 82 | integer, parameter :: prec = precision(1._wp) |
|---|
| 83 | |
|---|
| 84 | !~ contains |
|---|
| 85 | !~ !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 86 | |
|---|
| 87 | !~ !======================================================================= |
|---|
| 88 | !~ FUNCTION is_finite(var) RESULT(flag) |
|---|
| 89 | !~ !----------------------------------------------------------------------- |
|---|
| 90 | !~ ! NAME |
|---|
| 91 | !~ ! is_finite |
|---|
| 92 | !~ ! |
|---|
| 93 | !~ ! DESCRIPTION |
|---|
| 94 | !~ ! Returns whether array values are finite. |
|---|
| 95 | !~ ! |
|---|
| 96 | !~ ! AUTHORS & DATE |
|---|
| 97 | !~ ! JB Clement, 01/2026 |
|---|
| 98 | !~ ! |
|---|
| 99 | !~ ! NOTES |
|---|
| 100 | !~ ! Finite values are neither NaN nor Infinite. |
|---|
| 101 | !~ !----------------------------------------------------------------------- |
|---|
| 102 | |
|---|
| 103 | !~ ! DECLARATION |
|---|
| 104 | !~ ! ----------- |
|---|
| 105 | !~ implicit none |
|---|
| 106 | |
|---|
| 107 | !~ ! ARGUMENTS |
|---|
| 108 | !~ ! --------- |
|---|
| 109 | !~ real(dp), dimension(..), intent(in) :: var |
|---|
| 110 | |
|---|
| 111 | !~ ! LOCAL VARIABLES |
|---|
| 112 | !~ ! --------------- |
|---|
| 113 | !~ logical(k4) :: flag |
|---|
| 114 | |
|---|
| 115 | !~ ! CODE |
|---|
| 116 | !~ ! ---- |
|---|
| 117 | !~ flag = .false. |
|---|
| 118 | !~ if (all(ieee_is_finite(var))) flag = .true. |
|---|
| 119 | |
|---|
| 120 | !~ END FUNCTION is_finite |
|---|
| 121 | !~ !======================================================================= |
|---|
| 122 | |
|---|
| 123 | !~ !======================================================================= |
|---|
| 124 | !~ FUNCTION is_nan(var) RESULT(flag) |
|---|
| 125 | !~ !----------------------------------------------------------------------- |
|---|
| 126 | !~ ! NAME |
|---|
| 127 | !~ ! is_nan |
|---|
| 128 | !~ ! |
|---|
| 129 | !~ ! DESCRIPTION |
|---|
| 130 | !~ ! Returns whether array values has a Not-a-Number (NaN). |
|---|
| 131 | !~ ! |
|---|
| 132 | !~ ! AUTHORS & DATE |
|---|
| 133 | !~ ! JB Clement, 01/2026 |
|---|
| 134 | !~ ! |
|---|
| 135 | !~ ! NOTES |
|---|
| 136 | !~ ! |
|---|
| 137 | !~ !----------------------------------------------------------------------- |
|---|
| 138 | |
|---|
| 139 | !~ ! DECLARATION |
|---|
| 140 | !~ ! ----------- |
|---|
| 141 | !~ implicit none |
|---|
| 142 | |
|---|
| 143 | !~ ! ARGUMENTS |
|---|
| 144 | !~ ! --------- |
|---|
| 145 | !~ real(dp), dimension(..), intent(in) :: var |
|---|
| 146 | |
|---|
| 147 | !~ ! LOCAL VARIABLES |
|---|
| 148 | !~ ! --------------- |
|---|
| 149 | !~ logical(k4) :: flag |
|---|
| 150 | |
|---|
| 151 | !~ ! CODE |
|---|
| 152 | !~ ! ---- |
|---|
| 153 | !~ flag = .false. |
|---|
| 154 | !~ if (any(ieee_is_nan(var))) flag = .true. |
|---|
| 155 | |
|---|
| 156 | !~ END FUNCTION is_nan |
|---|
| 157 | !~ !======================================================================= |
|---|
| 158 | |
|---|
| 159 | !~ !======================================================================= |
|---|
| 160 | !~ FUNCTION is_normal(var) RESULT(flag) |
|---|
| 161 | !~ !----------------------------------------------------------------------- |
|---|
| 162 | !~ ! NAME |
|---|
| 163 | !~ ! is_normal |
|---|
| 164 | !~ ! |
|---|
| 165 | !~ ! DESCRIPTION |
|---|
| 166 | !~ ! Returns whether array values is normal. |
|---|
| 167 | !~ ! |
|---|
| 168 | !~ ! AUTHORS & DATE |
|---|
| 169 | !~ ! JB Clement, 01/2026 |
|---|
| 170 | !~ ! |
|---|
| 171 | !~ ! NOTES |
|---|
| 172 | !~ ! A normal value is finite, non-zero and not subnormal/denormal (very |
|---|
| 173 | !~ ! small finite number with reduced precision). |
|---|
| 174 | !~ !----------------------------------------------------------------------- |
|---|
| 175 | |
|---|
| 176 | !~ ! DECLARATION |
|---|
| 177 | !~ ! ----------- |
|---|
| 178 | !~ implicit none |
|---|
| 179 | |
|---|
| 180 | !~ ! ARGUMENTS |
|---|
| 181 | !~ ! --------- |
|---|
| 182 | !~ real(dp), dimension(..), intent(in) :: var |
|---|
| 183 | |
|---|
| 184 | !~ ! LOCAL VARIABLES |
|---|
| 185 | !~ ! --------------- |
|---|
| 186 | !~ logical(k4) :: flag |
|---|
| 187 | |
|---|
| 188 | !~ ! CODE |
|---|
| 189 | !~ ! ---- |
|---|
| 190 | !~ flag = .false. |
|---|
| 191 | !~ if (all(ieee_is_normal(var))) flag = .true. |
|---|
| 192 | |
|---|
| 193 | !~ END FUNCTION is_normal |
|---|
| 194 | !~ !======================================================================= |
|---|
| 195 | |
|---|
| 196 | END MODULE numerics |
|---|
| 197 | |
|---|