Fanning Software Consulting

Making IDL Operators Play Nice with NaNs

Facebook Twitter RSS Google+

QUESTION: The minimum and maximum operators do not work nicely with NaN values. Consider this code.

   IDL> a = Findgen(5)      
   IDL> a[2] = !Values.F_NaN 
   IDL> Print, a            
        0.00000      1.00000          NaN      3.00000      4.00000
   IDL> b = a > 2          
   % Program caused arithmetic error: Floating illegal operand
   IDL> Print, b 
        2.00000      2.00000      2.00000      3.00000      4.00000

I think most people would say that the proper behavior would be for the NaN value to be preserved. The IDL documentation indicates the behavior is actually hardware dependent, and on some machines the NaN is preserved. It suggests using Where and Finite instead of ">", whenever NaN values are present.

   IDL> b = a
   IDL> goodIndices = Where(Finite(a), count)
   IDL> IF count GT 0 THEN b[goodIndices] = a[goodIndices] > 2
   IDL> Print, b   
        2.00000      2.00000          NaN      3.00000      4.00000

The syntax above also eliminates the annoying "illegal operand" error message. The documentation also indicates that the ">" operator does not check for NaN values for speed reasons, and that the syntax of the operator does not allow having a NaN keyword be used with it.

A related problem occurs with the Hist_Equal function.

   IDL> Print, Hist_Equal(a)
        0  85   0 170 255
        % Program caused arithmetic error: Floating illegal operand

In this case, it is correct that the NaN is not preserved, since the output of Hist_Equal is a byte array. But I think it is a bug that the illegal operand error occurs. Hist_Equal does check for NaN values internally (for example, the internal Histogram command is called with the NaN keyword). It is only at the last step in Hist_Equal, where the > operator is used, that the NaN values are ignored. In this case, I think ExelisVis should follow their own advice and use Where and Finite rather than the > operator, even though doing so would make this a much slower operation.

Any ideas about this?

ANSWER: Well, I completely agree it is always best to follow your own advice, but you can see how far this gets you in your own life, probably.

I do note there is a faster way of obtaining the same result, without resorting to the Where and Finite functions, although you still get the dreaded illegal operand error, unfortunately. This syntax is about twice as fast as using Where and Finite for a normal size image.

  IDL> b = (a > 2) + a*0
        % Program caused arithmetic error: Floating illegal operand
  IDL> Print, b
        2.00000      2.00000          NaN      3.00000      4.00000

I suppose you can fix the error message by just turnning off exception handling while you are performing this operation.

  IDL> !Except = 0
  IDL> b = (a > 2) + a*0
  IDL> Print, b
        2.00000      2.00000          NaN      3.00000      4.00000
  IDL> void = Check_Math() & !Except = 1

Version of IDL used to prepare this article: IDL 8.2.3.

Written: 2 November 2013