Having parameter (constant) variable with NaN valu

2019-01-26 10:32发布

问题:

Is it possible to set a parameter variable with NaN? and have that in a particular module. I want to use it for initialization of some other variables. Therefore, I'll be faced with a run-time error, if they are not updated, rather than simulations running with some random numbers. I am using GFORTRAN.

回答1:

It is possible. You first have to find out which bit pattern represents one of the possible NaN values. You can store the bit pattern in an integer:

 use, intrinsic :: iso_fortran_env
 real(real64) x
 integer(int64) i
 x = 0
 x = 0/x
 print *, x
 print *, transfer(x, i)
end

It gives: -2251799813685248

Then you can initialize your variables using

real(real64), parameter :: nan64 =  transfer(-2251799813685248_int64, 1._real64)

Similarly for 32 bit variables you get the integer -4194304, so that you can do

real(real32), parameter :: nan32 =  transfer(-4194304_int32, 1._real32)

Many compilers have an option to do that for you for all real variables. As francescalus shows, in gfortran it is -finit-real=nan. Doing that manually gives you a finer control.

Disclaimer: Be careful when switching to a different platform. Endianness and other issues could play a role, even though I think it could be actually OK. I assumed an IEEE conforming CPU.


See, francescalus's answer for an alternative which uses a standard function. Unfortunately, it is not applicable for parameter constants, but is useful.



回答2:

To add to Vladimir F's answer I'll mention that gfortran 5.0 (but not earlier) supports the IEEE intrinsic modules.

Instead of

real x
x=0
x=0/x

one can use

use, intrinsic :: iso_fortran_env
use, intrinsic :: ieee_arithmetic
integer(int32) i
real(real32) x

x = ieee_value(x, ieee_quiet_nan)
i = transfer(x,i)

This gives you a little flexibility over which of the NaN values you get. You also needn't worry about any signalling invalid flag. [But note that asking for ieee_signaling_nan may not really give you that.]

Note that ieee_value() can't be used directly in initialization: a reference to it isn't a constant expression. For such use, take this approach to get the bit pattern and apply the method of the other answer.

You'll also need to ensure that there is the support for the features for each datatype.



回答3:

If you are stuck with a GFortran that does not have the intrinsic IEEE but does have the intrinsic iso_c_binding (like the one needed to build R on Windows), the following works and is equivalent to the C and R NaN (passes is.nan on R):

real(kind = c_double), parameter :: ONE = 1_c_double    
real(kind = c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', ONE)

Interestingly, real(kind = c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', 1_c_double) fails my check for is.nan.