Problems with NaN (not a number)

  1. ‹ Older
  2. 3 years ago

    Robert W

    25 Jan 2017 Western Canada

    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
  3. Jean-Yves P

    25 Jan 2017 Testers, Xojo Pro Europe (France, Besançon)

    you can str(yournumber) and then search for "NAN" inside it's working.

  4. Christian S

    25 Jan 2017 Testers, Xojo Pro, XDC Speakers, Third Party Store Germany

    or isNanMBS function.

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

  5. Robert W

    26 Jan 2017 Western Canada

    @ChristianSchmitz 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...."

  6. Michel B

    26 Jan 2017 Testers, Xojo Pro

    You can use isNumeric .

  7. Jean-Yves P

    26 Jan 2017 Testers, Xojo Pro Europe (France, Besançon)
    dim d as Double
    
    d = 0/0
    
    MsgBox str(d)
    
    if IsNumeric(d) then
    MsgBox "is numeric"
    end if

    "is numeric" is displayed on the screen ... so isnumeric thinks NAN is a numeric

  8. Michel B

    26 Jan 2017 Testers, Xojo Pro
    Edited 3 years ago

    Then use both isNumeric and

    if str(d) = "NaN" then
    //whatever
  9. Robert W

    26 Jan 2017 Western Canada

    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

  10. Michel B

    27 Jan 2017 Testers, Xojo Pro

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

  11. Robert W

    27 Jan 2017 Western Canada

    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.

  12. Jean-Yves P

    27 Jan 2017 Testers, Xojo Pro Europe (France, Besançon)

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

  13. Michel B

    27 Jan 2017 Testers, Xojo Pro
    Edited 3 years ago

    @Robert W I think you're confusing 'complicated' with 'reliable.'

    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.

  14. Markus W

    8 Mar 2017 #JeSuisHuman New Zealand, Auc...
    Edited 3 years ago

    @Robert W 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

    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
  15. Robert W

    8 Mar 2017 Western Canada

    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.
  16. Markus W

    8 Mar 2017 #JeSuisHuman New Zealand, Auc...

    @Robert W 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.

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

  17. Jean-Yves P

    8 Mar 2017 Testers, Xojo Pro Europe (France, Besançon)

    @Robert W Christian's function fail in 64 bit builds

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

  18. Markus W

    8 Mar 2017 #JeSuisHuman New Zealand, Auc...

    @Jean-YvesPochez 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.

  19. Robert W

    8 Mar 2017 Western Canada

    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.

  20. 2 years ago

    Steve K

    3 Oct 2018 Melbourne, Australia

    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:

     // 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 //

    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?

  21. Robert W

    3 Oct 2018 Western Canada

    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.

  22. Newer ›

or Sign Up to reply!