Precision and kinds
One type per kind
VecFor is written once, in src/lib/vecfor_RPP.INC, and compiled once per real kind of PENF by the preprocessor:
| Module | Type | Versors | Free functions | Components |
|---|---|---|---|---|
vecfor_R4P | vector_R4P | ex_R4P, ey_R4P, ez_R4P | normL2_R4P, angle_R4P, ... | real(R4P) |
vecfor_R8P | vector_R8P | ex_R8P, ey_R8P, ez_R8P | normL2_R8P, angle_R8P, ... | real(R8P) |
vecfor_R16P | vector_R16P | ex_R16P, ey_R16P, ez_R16P | normL2_R16P, angle_R16P, ... | real(R16P) |
vecfor_RPP | vector | ex, ey, ez | normL2, angle, ... | real(R8P), by default |
use vecfor re-exports all of them. The operators and the methods have the same names in every module; the free functions, the versors and the device routines carry the suffix of their kind.
Two types, one kind
vector and vector_R8P both have real(R8P) components, but they are two different types, defined in two modules: one cannot be assigned to the other, nor passed where the other is expected, nor combined with it by an operator; ex is not ex_R8P. Use one of them throughout a program, and copy the components where the two meet:
d%x = b%x ; d%y = b%y ; d%z = b%z ! d is a vector, b a vector_R8PKinds of scalars and of vectors
A scalar of any integer kind (I1P, I2P, I4P, I8P) or real kind (R4P, R8P, R16P) is accepted by every operator with a vector of any kind, and converted to the kind of the vector first, with real(s, kind): the result has the precision of the vector. The scalar arguments of the methods (angle= of rotate, tolerance=) and the matrices of .matrix., rotate(matrix=) and mirror(matrix=) must have the kind of the vector.
There are no operations between vectors of two kinds: convert by components, real(a4%x, R8P).
True quadruple precision
PENF defines R16P as a true quadruple precision kind (33 decimal digits, real128 with gfortran) only when it is compiled with -DPENF_R16P; otherwise R16P is R8P, and vector_R16P is double precision. The GNU and Intel FoBiS modes, the makefile and fpm.toml of VecFor define it, for PENF and VecFor alike: vector_R16P has real128 components, and the operators accept real(R16P) scalars.
The flag must reach PENF and VecFor alike. A build of your own (another build system, or the sources compiled in your project) passes -DPENF_R16P to both; with fpm, fpm.toml passes it to the PENF dependency too. Compiled for VecFor alone, the R16P and R8P versions of the operators clash as ambiguous generics.
A compiler without a 128-bit real kind, as nvfortran on x86-64, gets double precision: its FoBiS modes do not define the flag, and vector_R16P is a double precision vector there. precision(v%x) tells which build a program has: 33 or 15. Quadruple precision arithmetic is done in software on most processors, many times slower than double precision.
The default kind
vector, the versors ex, ey, ez and the unsuffixed functions have the kind R8P unless vecfor_RPP.F90 is compiled with one of -DDEFKIND_R4P, -DDEFKIND_R8P, -DDEFKIND_R16P, which make it R4P, R8P or R16P (the last one quadruple precision only where -DPENF_R16P is defined too). A program written with vector changes precision by a compiler flag; the explicit types keep theirs.