PDA

View Full Version : Detecting 1.#QNAN


pw317
08-25-2003, 04:28 PM
OOps, I put this in the wrong List.

I am gettinga value back in a real variable across the VB to FOrtran interface( a Dll) that returns "1.#QANAN". VB does not know how to interpret this, nor do I.
I cannot find anything on the forums about this. How can I detect this ahead of time ??

I remember from somewhere back this means 'not a number'. I am getting this due to some combination of invalid user data. I cannot check for this in VB. Is there a method in Fortran to detect 1.#qanan , like
if(rParm .eq. 1.#QNAN) then .....

tzeis
08-25-2003, 06:00 PM
We have a FAQ on NaNs in the FAQ portion of the forum. The link is:
<a href="http://forum.lahey.com/showthread.php?s=&threadid=29"> NaN in numeric output field</a>
Check this out, and if you still have questions, let us know.

pw317
08-25-2003, 06:07 PM
Yes, I saw that post. It tells me what it is but not how to detect it. Will a compare 1.#QNAN in an IF statement be True? Note: I am running a large Legacy application and this can occur in many different locations. Determining each place is not feasible.

tzeis
08-25-2003, 08:28 PM
There are a couple of ways to detect if an invalid operation has occurred.
You can't do it with a floating point numerical comparison like (x == nan) because they are not numbers, and won't compare.
One way is to use the INVALOP function to mask and detect when an invalid operation occurs. There is an example program in the Language Ref showing use of INVALOP. This routine is probably not what you need, because it would require testing after each operation that you suspect might be causing a NaN. This routine is also a non-standard extension, and is not too portable.
For your purposes, a better way might be to use a function that tests for the value of NaN. I have attached some example code showing how this might be done. This code is more portable, but the double precision version uses quad precision integers, which might not be supported by all compilers.

pw317
08-25-2003, 10:52 PM
Thanks for the code snippets. I trust this works but I have no way of knowing if it does. The code is a bit obtuse for me. Following is the function for real numbers you supplied.

function isnan(x) result(res)
real, intent(in) :: x
logical :: res

integer, parameter :: NaN = Z"FFC00000"

res = ieor(transfer(x,Nan), NaN) == 0
end function

What is the last line(res=...) supposed to be doing ??
(Obvioulsy, Fortran is not my native language!!)

Could you perhaps, add some comments along the way.
Also, tight code is never my prerogative.

tzeis
08-25-2003, 11:42 PM
Sorry for the lack of commenting. I am toying with the idea of making isnan a generic ELEMENTAL function (which means that in addition to a real scalar argument, you could pass it a real array and it would return a logical array, the argument could be of either single or double precision). I was intending that to be a more complete solution to the problem of detecting NaN's. What I sent you was more intended to get you going in the quickest possible fashion.
That said, comments are good.

I will explain the line:
res = ieor(transfer(x,Nan), NaN) == 0
First, we know that we cannot do a comparison of a floating pont NaN, because it is not a number. If we take the bit pattern, and transfer it to an integer variable, it does become a number, and we can compare it to another number. That is what the TRANSFER function is doing:
transfer(x,Nan)
takes the bit pattern from the real variable x, and transfers it to something that has the same type and kind as the integer variable NaN (which makes them comparable).
The IEOR function is then performing an "exclusive or" operation on the bits from the result of the TRANSFER function and the bits from the variable NaN:
ieor(transfer(x,Nan), NaN)
If they are identical bit for bit, the result of the operation will be zero.
Because the IEOR function returns an integer result, I can convert it to a logical type by comparing its result to zero:
ieor(transfer(x,Nan), NaN) == 0
TRANSFER and IEOR are Fortran 90 intrinsic functions. When writing utility functions like this, it is important to try to keep extra variables to a minimum, expecially when the function is ELEMENTAL. I could have used an integer variable to store the contents of the TRANSFER function, and that might have made the code more readable, but it would have doubled the memory load of the function. This might be of no consequence when you are calling it with a scalar argument, but if you call it from a program on the edge of using too much memory with a large array as an argument, the extra load might be the straw that breaks the camel's back.
I will post to this thread with a link to a more generalized and better commented solution to the detection problem, when I get one working.

pw317
08-26-2003, 01:53 AM
Ah, the light goes on. Thanks for the nice elucidation. In my case, I only have to test a couple of variables to know that things have gone awry and I can terminate early.

It's curious this hasn't come up as an issue before. Thanks for the solution.

tzeis
09-08-2003, 06:18 PM
I have posted a more complete solution to the problem of detecting Inf and NaN values. The url is: <a href="http://forum.lahey.com/showthread.php?s=&postid=10353#post10353">Testing for Inf and NaN Values</a>
The zip file contains a Fortran module containing a series of elemental functions that test for the IEEE values, and a small driver program.