The code modules described and referenced here are generic utilities used throughout a lot of other code available on this website.
For each integer and real data type there is a default kind and a processor- and compiler-dependent number of other kinds. The kind type definitions available in the Type_Kinds module are shown below in table 1 for integers, and table 2 for reals.
Kind types are specified based upon how a user thinks a number will be used, typically in terms of the size and/precision of a number to be stored as a variable or parameter. For example, the following
INTEGER, PARAMETER :: Double = SELECTED_REAL_KIND( 15 )defines a real kind type, Double, for variables that require a precision of at least 15 decimal digits. (See, for example, pg176 in "Fortran 90/95 Explained", 2nd Ed. by M.Metcalf and J.Reid, for a description of the SELECTED_REAL_KIND() intrinsic function.)
The real variable definition is then simply,
REAL( Double ) :: x
Kind Type Parameter | Description | |
---|---|---|
Byte | Kind type for a byte (1-byte) integer | |
Short | Kind type for a short (2-byte) integer | |
Long | Kind type for a long (4-byte) integer | |
LLong | Kind type for a double long (8-byte) integer. If this kind type is not supported by a compiler, the value defaults to Long. | |
IP_Kind | Kind type for a user specified default integer. The actual kind type this value corresponds to is determined by the PRIVATE IIP index. |
Kind Type Parameter | Description | |
---|---|---|
Single | Kind type for single precision (4-byte) real | |
Double | Kind type for double precision (8-byte) real | |
Quad | Kind type for quad precision (16-byte) real. If this kind type is not supported by a compiler, the value defaults to Double. | |
FP_Kind | Kind type for a user specified default real. The actual kind type this value corresponds to is determined by the PRIVATE IFP index. |
MODULE Type_Kinds IMPLICIT NONE INTEGER, PARAMETER :: Single = SELECTED_REAL_KIND( 6 ) INTEGER, PARAMETER :: Double = SELECTED_REAL_KIND( 15 ) INTEGER, PARAMETER :: fp_kind = Double END MODULE Type_Kinds PROGRAM Test_Kinds USE Type_Kinds REAL( fp_kind ) :: x, y x = 1.0_fp_kind y = x + 1.0_fp_kind END PROGRAM Test_KindsNote that a "generic" floating point kind type, fp_kind, has been defined. By using the generic kind type in the program, rather than the specific types Single or Double, the precision of the variables and literal constants used in the program can be changed simply by changing the definition of fp_kind in the Type_Kinds module and recompiling. This can be useful in identifying sections of an algorithm that are sensitive to the numerical precision of the variables it uses.
USE Type_Kinds REAL( fp_kind ) :: ppmv REAL( fp_kind ) :: Mixing_Ratio REAL( fp_kind ) :: Molecular_Weight ... ppmv = 1.0e+03 * Mixing_Ratio * 28.9648 / Molecular_WeightWhat is 1.0e+03? What is 28.9648? The code this example is taken from actually looks more like,
USE Type_Kinds REAL( fp_kind ), PARAMETER :: G_TO_KG = 1.0e-03_fp_kind REAL( fp_kind ), PARAMETER :: PPV_TO_PPMV = 1.0e+06_fp_kind REAL( fp_kind ), PARAMETER :: SCALE_FACTOR = G_TO_KG * PPV_TO_PPMV REAL( fp_kind ), PARAMETER :: MW_DRYAIR = 28.9648_fp_kind ... REAL( fp_kind ) :: ppmv REAL( fp_kind ) :: Mixing_Ratio REAL( fp_kind ) :: Molecular_Weight ... ppmv = SCALE_FACTOR * Mixing_Ratio * MW_DRYAIR / Molecular_WeightNow all of the "magic numbers" in the expression have been replaced with named parameter constants. Simply looking at the code tells us what the scaling factor is for and that the other number is actually the molecular weight of dry air. More importantly, note the suffix "_fp_kind" on all the literal constants in the parameter definitions. This ensures that the literal constant has the same precision as its data type. Remember that,
REAL( fp_kind ) :: x x = 35.6748assigns the default single precision value 35.6748 to the variable x regardless of the kind type of the actual variable. To ensure that literal constants of the correct precisions are assigned, the following is required,
REAL( fp_kind ) :: x x = 35.6748_fp_kindThis becomes particular important when variables are summed over many iterations. Assigning a single precision literal constant increases the possibilities of inaccuracies due to numerical precision errors accumulating.
Despite this, most of us still think in terms of 8-bit bytes (or 4-byte words) when we consider the "size" of an integer or real variable. For this reason, the Type_Kinds module contains defined parameters of the expected sizes of the various kinds of integers and reals in units of 8-bit bytes. These definitions are listed below in table 3 for integers and table 4 for reals.
Byte Size Parameter | Description | |
---|---|---|
n_Bytes_Byte | The expected size of a Byte kind integer in units of 8-bit bytes. | |
n_Bytes_Short | The expected size of a Short kind integer in units of 8-bit bytes. | |
n_Bytes_Long | The expected size of a Long kind integer in units of 8-bit bytes. | |
n_Bytes_LLong | The expected size of a LLong kind integer in units of 8-bit bytes. | |
n_Bytes_IP_Kind | The expected size of the user specified default integer kind in units of 8-bit bytes. The actual kind type size this value corresponds to is determined by the PRIVATE IIP index. |
Byte Size Parameter | Description | |
---|---|---|
n_Bytes_Single | The expected size of a Single kind real variable in units of 8-bit bytes. | |
n_Bytes_Double | The expected size of a Double kind real variable in units of 8-bit bytes. | |
n_Bytes_Quad | The expected size of a Quad kind real variable in units of 8-bit bytes. | |
n_Bytes_FP_Kind | The expected size of the user specified default real kind in units of 8-bit bytes. The actual kind type size this value corresponds to is determined by the PRIVATE IFP index. |
USE Type_Kinds REAL( fp_kind ) :: x, y IF ( x == y ) THEN ! -- x equals y, so perform some operation .... END IFMost people realise that real numbers should be compared within some tolerance value. However, a simple tolerance value will vary depending on the magnitudes of the numbers being compared. Without delving too much into the details, a better floating point comparison algorithm is,
IF ( ABS( x < y ) < ( ULP * SPACING( MAX(ABS(x),ABS(y)) ) ) ) THEN ! -- x equals y, so perform some operation .... END IFThe Fortran 90/95 intrinsic function SPACING(x) returns the absolute spacing of numbers near the value of x. The ULP value, the "unit in the last place", is the smallest possible increment or decrement that can be made using a machine's floating point arithmetic. A 0.5 ULP maximum error is the best you could hope for, since this corresponds to always rounding to the nearest representable floating point number. The ULP value can be used to scale the comparison based on knowledge of the "numerical quality" of the two numbers being compared.
This floating point comparison capability is provided in the Compare_Float_Numbers module via the logical Compare_Float() function. In addition, simple relational operators .EqualTo., .GreaterThan., and .LessThan. are also available. Both single and double precision numbers can be compared, as can arrays from rank-1 to rank-7. Using the previous example, the floating point number comparison for a particular ULP scaling becomes,
USE Type_Kinds USE Compare_Float_Numbers REAL( fp_kind ) :: x, y IF ( Compare_Float( x, y, ULP=5 ) ) ) THEN ! -- x effectively equals y, so perform some operation .... END IFFor no ULP scaling (ULP=1), the relational operator can be used instead,
USE Type_Kinds USE Compare_Float_Numbers REAL( fp_kind ) :: x, y IF ( x .EqualTo. y ) THEN ! -- x effectively equals y, so perform some operation .... END IFFor more detail on the subprograms, you can view the Compare_Float_Numbers module documentation.
USE Error_Handler CHARACTER( * ), PARAMETER :: ROUTINE_NAME = 'My_Routine' INTEGER :: Error_Status Error_Status = calculate_widget_size() IF ( Error_Status /= SUCCESS ) THEN CALL Display_Message( ROUTINE_NAME, & 'Error calculating widget size.', & Error_Status, & Message_Log = 'error_log.txt' ) RETURN END IFThe output message format is,
"routine name"("state description") : "message"
For example, if an error occurs in the Display_Message routine attempting to write to the log file, the output is,
DISPLAY_MESSAGE(FAILURE) : Error opening message log fileFor more detail on the subprograms, you can view the Error_Handler module documentation.
Error Code Parameter | Description | |
---|---|---|
SUCCESS | Code specifying successful completion. | |
INFORMATION | Code specifying information output. | |
WARNING | Code specifying a warning state. Execution can continue but results may be incorrect. | |
FAILURE | Code specifying severe error. Execution cannot continue. | |
UNDEFINED | Code specifying undefined completion status. |
The byte swapping is performed by using the TRANSFER intrinsic to rearrange the bytes of a data object by accessing the data with a subscript triplet having a negative stride. For example, for 4-byte integer swapping,
USE Type_Kinds INTEGER( Long ) :: Input INTEGER( Long ) :: Output INTEGER, PARAMETER :: N = n_Bytes_Long INTEGER( Byte ), DIMENSION( N ) :: Byte_Equivalent Byte_Equivalent = TRANSFER( Input, Byte_Equivalent ) Byte_Equivalent = Byte_Equivalent( N:1:-1 ) Output = TRANSFER( Byte_Equivalent, Output )
This method can be slow, not because of the TRANSFER function itself, but the negative stride of the array access. It depends on the quality of implementation of a compiler. Regardless, it is most definitely not recommended that the Swap_Endian function be used to byte-swap large quantities of data -- say if you're reading a big-endian file on a little-endian system. That sort of thing is better handled by appropriate compiler switches that access the requisite run time libraries.
Other methods tried included
CALL MVBITS( Input, 0, 8, Output, 24 ) ! Bits 0-7 --> 24-31 CALL MVBITS( Input, 8, 8, Output, 16 ) ! Bits 8-15 --> 16-23 CALL MVBITS( Input, 16, 8, Output, 8 ) ! Bits 16-23 --> 8-15 CALL MVBITS( Input, 24, 8, Output, 0 ) ! Bits 24-31 --> 0-8
For more detail on the available subprograms, you can view the Endian_Utility module documentation.
TYPE, PUBLIC :: Character_List_File_type PRIVATE INTEGER :: String_Length = STRLEN INTEGER :: n_Entries = 0 CHARACTER( STRLEN ), DIMENSION(:), POINTER :: Entry => NULL() END TYPE Character_List_File_type TYPE, PUBLIC :: Integer_List_File_type PRIVATE INTEGER :: n_Entries = 0 INTEGER, DIMENSION(:), POINTER :: Entry => NULL() END TYPE Integer_List_File_typeNote that while the data types themselves are decalred PUBLIC, their contents are PRIVATE and can only be obtained via the module functions.
For more detail on the available subprograms, you can view the List_File_Utility module documentation.
Parameter Name | Description |
---|---|
PI | Value of π |
PI_RECIPROCAL | Reciprocal value of π, 1/π |
PI_SQUARED | Squared value of π, π^{2} |
PI_SQUARE_ROOT | Square root value of π, √π |
PI_LN | Natural logarithm of π, LN(π) |
PI_LOG10 | Base-10 logarithm of π, LOG(π) |
E | Value of e, base of the natural logarithm |
E_RECIPROCAL | Reciprocal value of e, 1/e |
E_SQUARED | Squared value of e, e^{2} |
E_LOG10 | Base-10 logarithm of e, LOG(e) |
Parameter Name | Description | Units |
---|---|---|
SPEED_OF_LIGHT | Speed of light in a vacuum, c | metres/second, m/s |
PERMEABILITY | Permeability of free space, μ_{0} | Newton/Ampere^{2}, N/A^{2} |
PERMITTIVITY | Permittivity of free space, ε_{0} | Farad/metre, F/m |
PLANCK_CONSTANT | Planck's constant, h | Joule.seconds, Js |
GRAVITATIONAL_CONSTANT | Universal, or Newtonian, gravitation constant, G | m^{3}/(kg.s^{2}) |
Parameter Name | Description | Units |
---|---|---|
ELECTRON_VOLT | Electron volt, the work required to move one electron through a potential difference of one volt. | Joules, J |
UNIFIED_ATOMIC_MASS_UNIT | Unified atomic mass unit, u. This is a unit of mass equal to the mass of 1/12 of a mole of Carbon-12 atoms | kg |
STANDARD_ATMOSPHERE | Standard atmospheric pressure, P_{0}. | Pascals, Pa |
STANDARD_TEMPERATURE | Standard atmospheric temperature, T_{0}. Note that the unit of thermodynamic temperature, the Kelvin, is the fraction 1/273.16 of the thermodynamic temperature of the triple point of water. The standard temperature is the ice point of water, 273.15, not the triple point. | Kelvin, K |
STANDARD_GRAVITY | Standard acceleration of gravity, g | m/s^{2} |
Parameter Name | Description | Units |
---|---|---|
AVOGADRO_CONSTANT | Avogadro's number, N(A). The number of atoms or molecules required such that the number of grams of a substance equals its atomic mass. This number of atoms or molecules is a mole. | mol^{-1} |
MOLAR_GAS_CONSTANT | Universal gas constant, R | J/(mol.K) |
BOLTZMANN_CONSTANT | Boltzmann's constant, k, where k=R/N(A) | J/K |
STEFAN_BOLTZMANN_CONSTANT | Stefan-Boltzmann constant, σ | W/(m^{2}.K^{4}) |
C_1 | First radiation constant for spectral radiance, c_{1}, where c_{1}=2.h.c^{2} | W.m^{2}.sr^{-1} |
C_2 | Second radiation constant, c_{2}, where c_{2}=h.c/k | K.m |
STP_MOLAR_VOLUME | Molar volume, V_{m}, of an ideal gas at standard temperature and pressure | m^{3}/mol |
LOSCHMIDT_CONSTANT | The number density, n_{0}, of one mole of an ideal gas at standard temperature and pressure | m^{-3} |