Problems with NaN (not a number)

I realize that this is an old thread, but I recently had the need to detect when a math operation returns a bad value. I thought I’d seen an IsNaN function in the documentation, but apparently I’d been dreaming, or thinking of some other programming language. Anyway, I came up with the following, which is simpler than converting the result to string and looking for string patterns.

Public Function IsNaN(x As Double) as Boolean
  return (x*0<>0)
End Function

you can str(yournumber) and then search for “NAN” inside it’s working.

or isNanMBS function.

Or simply if x <> x then as Nan will not compare to itself.

I think that’s effectively the same thing as what I posted. I was simply trying to point out that it’s not necessary to convert the number into a string and then search for “NAN…”

You can use isNumeric.

[code]dim d as Double

d = 0/0

MsgBox str(d)

if IsNumeric(d) then
MsgBox “is numeric”
end if[/code]

“is numeric” is displayed on the screen … so isnumeric thinks NAN is a numeric

Then use both isNumeric and

if str(d) = "NaN" then //whatever

I don’t understand obsession of doing a string conversion. Why make it more complicated than necessary?

I just ran a comparison between my IsNaN function, and Christian’s suggestion of using “x<>x”. Here are the results:


Invalid
Operation   x*0<>0   x<>x

log(0)      True     False
log(-1)     True     True 
sqrt(-1)    True     True 
1/0         True     False 
-1/0        True     False 
exp(1e40)   True     False 

Valid
Operation   x*0<>0   x<>x

100         False    False 
0/5         False    False 
2+4         False    False 

The x<>x comparison fails in many cases, apparently because it doesn’t detect +inf or -inf

I rather go for an “obsessive” string conversion and have a reliable result.

I think you’re confusing ‘complicated’ with ‘reliable.’

The IEEE floating point spec is well documented. If the result of an operation results in a Nan or Inf etc., then that result will propagate along any further operations. In that regard, multiplying a Nan or Inf by zero will result in a Nan or Inf, whereas multiplying a valid number by zero will always result in zero. So, multiplying by zero quite clearly distinguishes a Nan from a valid number. These are operations that happen at the processor level, avoiding the guesswork about how a programming language (eg., Xojo) is going to translate the value into a string, which could possibly vary from one version to the next.

Anyway, I’ve presented a simple, fast and reliable method to detect invalid numbers. People can use it or not. I have nothing more to say.

with the str thing, I can check for NAN but also easy the same way for +INF or -INF …

Don’t be upset. There is never one unique way of doing things. If people don’t adopt your method, it is not the end of the world.

[quote=312179:@Robert Weaver]I don’t understand obsession of doing a string conversion. Why make it more complicated than necessary?

I just ran a comparison between my IsNaN function, and Christian’s suggestion of using “x<>x”. Here are the results:


Invalid
Operation   x*0<>0   x<>x

log(0)      True     False
log(-1)     True     True 
sqrt(-1)    True     True 
1/0         True     False 
-1/0        True     False 
exp(1e40)   True     False 

Valid
Operation   x*0<>0   x<>x

100         False    False 
0/5         False    False 
2+4         False    False 

The x<>x comparison fails in many cases, apparently because it doesn’t detect +inf or -inf[/quote]

No.

Let’s just look at passing 1/0 to your function (just follow it in the debugger):

1/0 is INF.
INF * 0 is NaN.
NaN is <> 0 so you return TRUE for the IsNaN function.

But the argument passed to your IsNaN function was INF, not NaN, so you return the wrong value.

Christian’s function works (even if you pass 1/0 aka INF or -1/0 aka -INF to it):

Public Function IsNaN(x As Double) as Boolean return x<>x End Function

Yes, I pointed that out in my earlier post; it returns true for NaN, inf and -inf, which is what I find most useful for my needs. If you need to distinguish between these three results, then Christian’s suggestion of using the x<>x test will return true only for NaN’s.

I also need to post a warning about using these functions. Michel was correct about reliability. I was testing these again today, and discovered that both my function And Christian’s function fail in 64 bit builds. I came up with a workaround for my function, but haven’t yet attempted a workaround for Christian’s.

Public Function IsNaN1(x As Double) as Boolean
  #If Target32Bit
    return (x*0<>0)
  #Else
    Return not(x*0<>0 or x*0=0)
  #Endif
End Function

But please note that this has only been tested on Macintosh builds. So, if you wish to use it, then it should be tested on whichever hardware it’s to be deployed on.

Because of this inconsistency, I decided to look at other ways of testing for NaN’s. The most direct is to look at the bit pattern of the result of the mathematical operation. So, I came up with this alternative function:

Public Function IsNaN2(x As Double) as Boolean
  'Test for invalid number: NaN, +inf, -inf
  static m As new MemoryBlock(8)
  m.DoubleValue(0) = x
  Return Bitwise.BitOr(m.Int64Value(0),&h800fffffffffffff)=-1
End Function

This can easily be modified to distinguish between NaN, inf and -inf.

For comparison purposes, I also put together a string based function:

Public Function IsNaN3(x As Double) as Boolean
  return InStr(str(x),"N")>0
End Function

Speed testing these three functions by running each one 10 million times, I get the following results:

Function     Time (32 bit)     Time (64 bit)
--------     -------------     -------------
IsNan1        2.773251 sec.     0.5279456 sec.
IsNan2        2.395691 sec.     1.862914 sec.
IsNan3       12.01183 sec.      9.931013 sec.

You should not call your function IsNaN then … the name should always clearly reflect what it does.

isn’t it a xojo bug instead of a christian bad method ?

Depends. Christian’s method relies on NaN not comparing to itself. I don’t think that is documented anywhere.

In my opinion, it’s a Xojo bug.
The IEEE 754 specification which defines the standard double floating point format, and which defines NaN’s, also specifies how NaN’s should behave with comparison operators. Assuming that Xojo follows the IEEE 754 specification, then there must be a bug in either the 32 bit build or the 64 bit build, because the 32 and 64 bit builds should be consistent if they conform to IEEE 754.

Hey guys, I really really would prefer not to be a part of this thread because it’s beyond my understanding, but I do need to know where things are at with this issue.

I’ve read this post a few times but there is no clear answer, (except maybe for Robert Weavers information in the preceding post.) There seems to be a lot of ideas thrown around, but no clear cut solution. Although Kems solution was looking good, then is seemed to be disregarded because of an apparent flaw.

I’m certainly not offering a solution. I just need an answer.

I’ve had the issue before (about a year ago) and it wasn’t a big deal because it was a “display” issue and never affected any important calculations. I got around it something like this:

[code] // detect if nan or Inf
If InStr (showCurrentGs,“Inf”) <> 0 Then
showCurrentGs = “0.0”
End If

If InStr (showCurrentGs,“nan”)<> 0 Then
showCurrentGs = “0.0”
End If //[/code]

However, now I have a situation where a number is calculated and sent to an external device. I believe I’m getting (-Nan) and the external device becomes corrupt. Although it can be reset (via software), this is not an acceptable scenario.

I haven’t done any more work on my software for the last week because I this issue. I’ve done some reading but want to make sure the solution is as foolproof as possible.

I guess I could try InStr as before - or is Kems solution better?

The Regex solution appears to be more intended to check the validity of user input. If your variable showCurrentGs is the direct output of a numeric calculation, then it will either be a valid number, or it will be a NaN, or inf. So your test will work fine as is. In fact you can simplify it to a single test to look for the character “n” which would never appear in a normal number.

// detect if nan or Inf If InStr (showCurrentGs,"n") <> 0 Then showCurrentGs = "0.0" End If

This is essentially the same code as the IsNan3 function that I posted above.