When interfacing a piece of Fortran 2003 (or above) code with MATLAB by MEX, I am surprised to find that MEX changes the kind of the default logical. This is fatal, because a piece of perfectly compilable Fortran code may fail to be mexified due to a mismatch of types, which did happen in my project.
Here is a minimal working example.
Name the following code as "test_kind.F", compile it by mex test_kind.F
in MATLAB, and then run test_kind
in MATLAB. This will produce a plain text file named fort.99, which contains two numbers "4" and then "8" as the result of the WRITE instructions.
! test_kind.F
! Tested by MATLAB 9.8.0.1323502 (R2020a) with GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
#include "fintrf.h"
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
use ieee_arithmetic, only : ieee_is_nan
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
write(99, *) kind(ieee_is_nan(1.0)) ! This prints a number in fort.99
write(99, *) kind(.false.) ! A benchmark, which should print the same number in fort.99
close(99)
end subroutine mexFunction
I thought the two printed numbers should always be equal to each other, although the specific value depends on the compiler and needs not to be 4 or 8. (As stressed by Doctor Fortran @SteveLionel, the Fortran standard imposes no relation between these kind numbers and the number of bytes used to represent the data. See Steve's blog Doctor Fortran in “It Takes All KINDs” for a nice elaboration on this topic.)
[Update: The above speculation about kind(ieee_is_nan(1.0)=kind(.false.)
turns out wrong even though it is what the Fortran 2018 standard suggests. With certain compiler options, kind(ieee_is_nan(1.0)
and kind(.false.)
can actually differ from each other and hence violate the specifications in the Fortran standard. See the answer by @francescalus and my summary at the end of this question.]
[Update: in the original question, I flipped "4" and "8", so that I thought kind(ieee_is_nan(1.0))
was changed; indeed, it is kind(.false.)
that is altered from 4 to 8, while kind(ieee_is_nan(1.0))
remains 4 always. So everything is fully explained by the nice answer from @francescalus, thank you!]
For comparison, here is the same code without interfaced with MATLAB, which prints "4" and "4" on the screen when compiled with gfortran. With the nagfor compiler, the numbers remain equal although become 3.
! test_kind.f90
! Tested by GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
program test_kind
use ieee_arithmetic, only: ieee_is_nan
implicit none
write(*, *) kind(ieee_is_nan(1.0)) ! This prints a number on STDOUT (screen)
write(*, *) kind(.false.) ! A benchmark, which should print the same number on STDOUT (screen)
end program test_kind
For your reference, below is the section on ieee_is_nan
in the Fortran 2018 standard. It specifies that the ieee_is_nan
returns a "default logical", which I guess should be identical to the type of the intrinsic .true.
or .false.
constant --- or did I get it wrongly?
17.11.13 IEEE_IS_NAN (X)
1 Description. Whether a value is an IEEE NaN.
2 Class. Elemental function.
3 Argument. X shall be of type real.
4 Restriction. IEEE_IS_NAN (X) shall not be invoked if IEEE_SUPPORT_NAN (X) has the value false.
5 Result Characteristics. Default logical.
6 Result Value. The result has the value true if the value of X is an IEEE NaN; otherwise, it has the value false.
It seems extraordinary to me that MEX can change the type of the default logical without taking care of ieee_is_nan
. Maybe there exists an option of MEX that can rectify this behavior, but why should it be the default in the first place?
I tried the same code on more machines with other versions of MATLAB and Fortran compiler. The results are the same.
MATLAB 9.7.0.1319299 (R2019b) Update 5 with GNU Fortran (GCC) 8.3.1 20191121 (Red Hat 8.3.1-5):
kind(ieee_is_nan(1.0))= 4, kind(.false.) = 8
The same compiler without interfacing with MATLAB:
kind(ieee_is_nan(1.0)) = 4 = kind(.false.)
MATLAB 9.5.0.1049112 (R2018b) Update 3 with GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0:
kind(ieee_is_nan(1.0)) = 4, kind(.false.) = 8
The same compiler without interfacing with MATLAB:
kind(ieee_is_nan(1.0)) = 4 = kind(.false.)
(On Windows 10) MATLAB 9.5.0.944444 (R2018b) with Intel(R) Visual Fortran Intel (R) 64 Compiler, Version 19.1.1.216 Build 20200306
kind(ieee_is_nan(1.0)) = 4, kind(.false.) = 8
The same compiler without interfacing with MATLAB:
kind(ieee_is_nan(1.0)) = 4 = kind(.false.)
A summary after accepting @francescalus' answer
It turns out that the mismatch between
kind(.false.)
andkind(ieee_is_nan(1.0))
comes from the gfortran option-fdefault-integer-8
, which is adopted by MEX as the default. This option enforces gfortran to use 64-bit integer and 64-bit logical as the default kind, but does not change the returned kind ofieee_is_nan
, even though the Fortran standard specifies thatieee_is_nan
should return the default logical kind. This may be becauseieee_is_nan
is not really an intrinsic procedure but only a procedure from the intrinsic moduleieee_arithmetic
.Note that ifort (version ifort (IFORT) 2021.2.0 20210228) and nagfor (NAG Fortran Compiler Release 7.0 (Yurakucho) Build 7036) behave also in the way described above, the corresponding option being
-i8
for both of them. So the compiler vendors agree that it is fine to break the consistency of some intrinsic modules when certain options are enforced. This is surprising to me. Fortunately, flang (under clang 7.1.0) follows the Fortran standard even with-fdefault-integer-8
imposed, keepingkind(is_ieee_nan(1.0)) == kind(.false.)
--- so it is not a mission impossible.The NAG compiler nagfor warns about
ieee_is_nan
when-i8
is adopted, pointing out that they are incompatible; gfortran and ifort, however, keep absolutely silent even if you invoke them with-Wall -Wexta
and-warn all
respectively. This is even more surprising to me.Given these facts, I decide not to use
ieee_is_nan
but to implement my ownis_nan
and stay vigilant about (or away from) all the procedures provided by intrinsic modules. Otherwise, my package will fail to compile due to a mismatch of types if the users choose to enforce the 64-bit integer as the default (without thinking about the logical kind; why should they?). More seriously, MATLAB has already made such a choice for all its users without telling them.I am happy to see that my question leads to interesting discussions. Since some compilers seem to be in need of improvements regarding the problems discovered here (you may have different opinions), I made a post on Fortran Discourse about this topic. I hope that it will draw more attention from the community and someone will patch at least the open-source compilers like gfortran.
Thank you very much for any comments or criticism.
ieee_is_nan
is not a (standard) intrinsic procedure. – Morelos