Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Use of signaling nan

Andrew_Smith
Valued Contributor I
1,895 Views

I have been liberally using non-signalling nans as a debug aid. I can use these anywhere an initialization expression is allowed. But having no signalling limits the usefulness of this method.

I tried to make use of the new option Qinit:snan but that is only applicable to local scalars which are a small subset of the cases I need.

I create a parameter for my initialization like this:

real(DP), parameter :: aNaN = 0.0D0 / 0.0D0.

and declare arrays within derived types like this:

type Bar
   real(DP) :: vec(3) = [aNaN, aNaN, aNaN]
end type

So why not change the declaration of aNaN to a signalling version I thought. But having done so it still does not trap.

This code demonstrates that even if my aNaN parameter has the same bit pattern as Qinit:snan it fails to trap assignment. I also tried the portable IEEE_VALUE function to get a signalling nan it it did not trap either.

program TestSignalingNaN
   implicit none
   
   integer, parameter :: DP = 8
   real(DP), parameter :: aNaN = z'7FFFBADDADBADDAD' !Value from Qinit:snan
   real(DP), parameter :: bNaN = z'7FFC000000000000' !IEEE_VALUE(1.0_DP, IEEE_SIGNALING_NAN)
   real(DP), save :: cNaN
   
   real(DP) :: a
   a = aNaN
   a = bNaN
   a = cNaN !Only this assignment gets trapped
end program

The setting for fpe: flag does not appear to make any difference.

0 Kudos
7 Replies
Andrew_Smith
Valued Contributor I
1,895 Views

The assignment of cNaN gets trapped in default 32 bit debug configuration (windows) but the 64 bit version traps nothing !

Using compiler      Intel(R) Visual Fortran Compiler XE 15.0.3.208

0 Kudos
Steven_L_Intel1
Employee
1,895 Views

My observation is that you get the trap when the value is used, not on assignment. But I can't completely explain the behavior and will talk to the developers about it.

0 Kudos
andrew_4619
Honored Contributor III
1,895 Views

Slightly confused, was there something missing in the code snipped? In a = cNaN, cNan is uninitialised or is it initialised to nan by compiler option....?

0 Kudos
Steven_L_Intel1
Employee
1,895 Views

cNaN would have been set to a SNaN by the compiler when /Qinit:snan was used.

0 Kudos
FortranFan
Honored Contributor III
1,895 Views

How about this?

program p

   use, intrinsic :: iso_fortran_env, only : r8 => real64
   use, intrinsic :: ieee_arithmetic, only : ieee_value, ieee_signaling_nan, ieee_quiet_nan
   use, intrinsic :: ieee_exceptions , only : ieee_invalid, ieee_set_halting_mode

   implicit none

   real(r8) :: a
   real(r8) :: b

   call ieee_set_halting_mode(ieee_invalid, .true.)

   a = ieee_value(real(0.0, kind(r8)), ieee_quiet_nan)
   print *, " a = ", a

   b = ieee_value(real(0.0, kind(r8)), ieee_signaling_nan)
   print *, " b = ", b

   stop

end program p
  a =  NaN
forrtl: error (65): floating invalid
Image              PC                Routine            Line        Source

p64.exe            000000013FA21932  MAIN__                     17  p.f90
p64.exe            000000013FAC6B7E  Unknown               Unknown  Unknown
p64.exe            000000013FAC764C  Unknown               Unknown  Unknown
p64.exe            000000013FAC778E  Unknown               Unknown  Unknown
kernel32.dll       0000000076BA59BD  Unknown               Unknown  Unknown
ntdll.dll          00000000772BA551  Unknown               Unknown  Unknown

 

0 Kudos
Andrew_Smith
Valued Contributor I
1,895 Views

FortranFan , although your excellent code has the advantage of standard conformance it is not code that could be used to provide default initialization. For that we need a constant parameter.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,895 Views

Copy operations may be difficult to trap. This is because, the copy could use general purpose registers, or it could use integer SIMD instructions.

If you want to assure a trap in debug mode, force an expression on the variable.

#define test_snan(x) (x + 0.0_D)

If the compiler optimizes that out, then make the test a call to an external function that does not get inlined, and is not optimized.

I agree with your desire to have /Qinit:snan, at least in Debug build, use instructions that will cause a trap on simple assignments. This could be done with the add literal 0.0. as part of the assignment.

Jim Dempsey

0 Kudos
Reply