Topic: Using I=TRANSFER (X,I) to detect Inf and NaN?

Hi Jeff,

I have a question regarding the detection of numeric values that return Infinity (Inf) and Not-a-Number (NaN).
I've observed that the TRANSFER() function can be used to detect +Inf, -Inf, and NaN occurrences when its value is compared to four different integer values.

For single-precision reals, these transfer function integers are,
I value = -8388608       (represents -Infinity)
I value =  2139095040  (represents +Infinity)
I value = -4194304       (represents NaN)
I value = 2143289344   (represents NaN)

And for double-precision reals, the transfer function integers are,
I value = -4503599627370496       (represents -Infinity)
I value =  9218868437227405312  (represents +Infinity)
I value = -2251799813685248       (represents NaN)
I value =  9221120237041090560  (represents NaN)

Using SF, I was able to easily detect the occurrences of -Inf, +Inf, and NaN in a program. I've attached some code that provides a little more detail below.

My question is, simply, is this relationship of Transfer() functions of reals to integers representing Inf and NaN compiler specific?
In other words, would different compilers use different identifiable integers representing +Inf, -Inf, and NaN?

Although this relationship was new to me, perhaps it is more commonly known.

Regards,
Frank

!-----------------------------------------------------------------------
!
!  Single-precision IsReal4.f90
!
    INTEGER(KIND=4)          :: I      !--- (KIND=4)

    !--- rNEGINF equivalent I value = -8388608     (-Infinity)
    !--- rPOSINF equivalent I value =  2139095040  (+Infinity)
    !--- rNAN1   equivalent I value = -4194304     (NaN)
    !--- rNAN2   equivalent I value = 2143289344   (NaN)
    REAL(KIND=4), PARAMETER  :: rNEGINF = 8388608.0
    REAL(KIND=4), PARAMETER  :: rPOSINF = 2139095040.0
    REAL(KIND=4), PARAMETER  :: rNAN1   = 4194304.0
    REAL(KIND=4), PARAMETER  :: rNAN2   = 2143289344

    !--- TRANSFER REAL NUMBER TO INTEGER VALUE
    I = TRANSFER ( X, I )
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------
!
!  Double-precision IsReal8.f90
!
    INTEGER(KIND=8)           :: I     !--- (KIND=8)

    !--- rNEGINF equivalent I value = -4503599627370496     (-Infinity)
    !--- rPOSINF equivalent I value =  9218868437227405312  (+Infinity)
    !--- rNAN1   equivalent I value = -2251799813685248     (NaN)
    !--- rNAN2   equivalent I value =  9221120237041090560  (NaN)
    REAL(KIND=8), PARAMETER  :: rNEGINF =  4503599627370496.0
    REAL(KIND=8), PARAMETER  :: rPOSINF =  9218868437227405312.0
    REAL(KIND=8), PARAMETER  :: rNAN1   =  2251799813685248.0
    REAL(KIND=8), PARAMETER  :: rNAN2   =  9221120237041090560.0

    !--- TRANSFER REAL NUMBER TO INTEGER VALUE
    I = TRANSFER ( X, I )
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------   
!
!   Test for NaN, Inf, and real number
!
    R = REAL( ABS(I) )

    IF (ABS(R - rNEGINF) < eps) THEN
        !--- -Infinity
        IFLAG = -1
    ELSEIF (ABS(R - rPOSINF) < eps) THEN
        !--- +Infinity
        IFLAG = +1
    ELSEIF ((ABS(R - rNAN1) < eps).OR.(ABS(R - rNAN2) < eps)) THEN
        !--- NaN
        IFLAG = 2
    ELSE
        !--- Real number
        IFLAG = 0
    END IF
!-----------------------------------------------------------------------

2 (edited by jeff 2025-06-25 14:54:35)

Re: Using I=TRANSFER (X,I) to detect Inf and NaN?

Frank,

Your scheme should work as long as the underlying system conforms to IEEE-754 mathematics.  The Fortran standard does require IEEE-754 math, and I'm not aware of any modern CPU architectures that aren't using it at this point.  The last one to eschew that standard was maybe VAX.  EDIT: Some optimizations can cause the compiler and/or CPU to ignore the standard in favor of speed.

You might instead want to look at the Fortran 2003 ieee_arithmetic module, which our compiler does support.  The documentation is severely lacking, but the module does provide:

    ieee_is_finite(x) – determine if a value is finite.
    ieee_is_nan(x) – determine if a value is IEEE NaN

The module is part of the Fortran standard, so it might be a more reliable route.

There is some explanation at the Fortran wiki.

Jeff Armstrong
Approximatrix, LLC

Re: Using I=TRANSFER (X,I) to detect Inf and NaN?

Thanks Jeff,

I've tried using USE IEEE_ARITHMETIC, ONLY: IEEE_IS_NAN, IEEE_IS_FINITE in SF, but could not achieved the expected NaN or +/- Inf results as was observed using my I=Transfer(x,I) approach.

Frank

Re: Using I=TRANSFER (X,I) to detect Inf and NaN?

Jeff,

My error, you were correct that IEEE_IS_NAN and IEEE_IS_FINITE can be used successfully in SF with the expected Finite and NaN results of real numbers. I mistaken took the results of IEEE_IS_FINITE to mean INFINITE. Oops, sorry.

Frank