7

Some math functions in a program I recently wrote are returning unacceptable values, such as NaN (possibly due to not checking some function's input params). The problem is that it's being quite difficult to track down which functions are passing the wrong values. This results in errors being propagated throughout the code and making the program crash minutes or hours later, if at all.

I wonder if there's a way to catch these faulty operations the moment a NaN value results from any operation (pretty much the same as in the 'DivisionByZero exception' thrown by some C/C++ compilers, if I remember).

Thanks in advance.

P.D: Please feel free to re-tag my question if needed.

Trap
  • 12,050
  • 15
  • 55
  • 67
  • 1
    It seems to me like this is a case where incorporating testing into the development should be considered. If your math functions are not too many you might want to properly define pre- and postconditions and write tests for them to avoid them returning NaN in the first place. – Frank Feb 12 '10 at 11:54
  • In this case accessing an array where the index = (long)NaNvalue, but it could have been anything else. – Trap Feb 12 '10 at 11:57
  • @Frank Yeah, that's how I should have done that, but I didn't and that's why I'm here asking :) – Trap Feb 12 '10 at 12:06

6 Answers6

10

Without seeing your code this answer is going to be necessarily vague, but one way of doing it is to check the output from your function and if it's "NaN" raise and exception:

if (double.IsNaN(result))
{
    throw new ArithmeticException();
}

But with more details about the exception.

UPDATE

To trap where a specific exception is being thrown you could (temporarily) break when the exception is thrown in the debugger.

Select Debug > Exceptions then expand the tree to select Common Language Runtime Exceptions > System > System.ArithmeticException and check the "Thrown" option.

The problem with this is that it will break everywhere this is thrown, not just in your code. Putting explicit code at a low enough level gets around this.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
  • 1
    What I want to do is to catch where the NaN value is produced without having to debug the whole application and writing a check like yours on every method that accepts doubles. – Trap Feb 12 '10 at 12:08
  • 1
    I have the same problem, but the value that is bugging me isn't NaN but 'Infinity'. I checked the System.ArithmeticException as described above, but it doesn't fire, when my varibale is set to 'Infinity'. Is there an other Exception to check the Thrown option? – Aaginor Oct 06 '10 at 16:36
  • @Aaginor - you want the [`Double.IsInifinity`](http://msdn.microsoft.com/en-us/library/system.double.isinfinity.aspx) method – ChrisF Oct 06 '10 at 19:39
  • 1
    Like Trap, I want to catch when the Infinite value is produced, to get to know where the problematic part in my code is to be able to fix it - without the need to step through each single line to find out, where it is. – Aaginor Oct 07 '10 at 10:19
7

This question seems to be a little older, but since I stumbled about the same problem: Alexander Torstling's answer and the comments below work actually well for me.

What's nice is that even though c# does not provide it's own way for enabling floating point exceptions, it can still catch them (for c++ you need a conversion first).

C#-code is here:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace ConsoleApplication2
{
  class Program
  {
    [System.Runtime.InteropServices.DllImport("msvcrt.dll")]
    public static extern uint _control87(uint a, uint b);

    [System.Runtime.InteropServices.DllImport("msvcrt.dll")]
    public static extern uint _clearfp();

    static void Main(string[] args)
    {
      float zero = 0.0f - args.Length; // Want 0.0f. Fool compiler...
      System.Console.WriteLine("zero = " + zero.ToString());

      // A NaN which does not throw exception
      float firstNaN = zero / 0.0f;
      System.Console.WriteLine("firstNaN= " + firstNaN.ToString());

      // Now turn on floating-point exceptions
      uint empty = 0;
      uint cw = _control87(empty, empty); // Debugger halts on this one and complains about false signature, but continue works.
      System.Console.WriteLine(cw.ToString());
      uint MCW_EM = 0x0008001f; // From float.h
      uint _EM_INVALID = 0x00000010; // From float.h (invalid corresponds to NaN
      // See http://www.fortran-2000.com/ArnaudRecipes/CompilerTricks.html#x86_FP

      cw &= ~(_EM_INVALID);
      _clearfp(); // Clear floating point error word.
      _control87(cw, MCW_EM); // Debugger halts on this one and complains about false signature, but continue works.      
      System.Console.WriteLine(cw.ToString());

      // A NaN which does throw exception
      float secondNaN = 0;
      try
      {
        // Put as much code here as you like.
        // Enable "break when an exception is thrown" in the debugger
        // for system exceptions to get to the line where it is thrown 
        // before catching it below.
        secondNaN = zero / 0.0f;
      }
      catch (System.Exception ex)
      {
        _clearfp(); // Clear floating point error word.
      }      

      System.Console.WriteLine("secondNaN= " + secondNaN.ToString());
    }
  }
}

The exception I get is {"Overflow or underflow in the arithmetic operation."} System.Exception {System.ArithmeticException}

Not sure why the debugger complains about the signature of _control87; anybody who can improve on that? "Continue" works fine for me, though.

Michael Brandl
  • 116
  • 1
  • 3
  • Change DLLImport into `[System.Runtime.InteropServices.DllImport("msvcrt.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]` and it won't complain anymore – PiotrK Dec 16 '22 at 06:59
5

I don't know if this works on the CLR, but you can use _controlfp_s from to trigger floating point exceptions:

unsigned int _oldState;
errno_t err = _controlfp_s(&oldState, 0, MCW_EM);
assert(!err);

To reset:

errno_t err = _controlfp_s(0, _oldState, MCW_EM);
assert(!err);
Alexander Torstling
  • 18,552
  • 7
  • 62
  • 74
  • You linked CRT (the C runtime library) help page, and at the bottom is indicates that this does not apply to the .NET runtime. OTOH, it does mention that you could use P/Invoke to call the C function. – Lucas Feb 12 '10 at 12:24
  • I'm not a .NET user, but it seems reasonable to assume that C# uses normal floating point instructions, and this should then be caught. If C# doesn't mess with these flags, _EM_INVALID should be triggered for NaNs, and if the mask is off you should get an FP exception. – Alexander Torstling Feb 12 '10 at 12:28
  • I also know that these exceptions are turned off by default in VC++ programs, so it could be worth a shot. – Alexander Torstling Feb 12 '10 at 12:30
  • Thanks, but this does not seem to have an effect for me. – gatopeich Apr 05 '13 at 10:08
3

Do you mean you are looking for some setting or option so that as soon as any int gets assigned the value NaN you want an exception to throw? I'm pretty sure no such thing exists. There is the checked option which will warn you about overflows, but thats not the same thing.

I think the only alternative to debugging by hand is to modify the code in the way ChrisF suggested. You could always put an #if DEBUG around the throw to stop if throwing in production code.

Steve
  • 8,469
  • 1
  • 26
  • 37
2

You could create a class that defines the same operations as an int (or a double), which wraps the int (or double). This class would check for NaN after every operation (N.B. it will be much slower than a simple int or double).

In your code, you would then use this new class everywhere there is an int (or double, respectively). You could even use a template type TIntegerType in your code to decide if you want an int or your class SafeInt.

There may be some who wouldn't like this approach, but I've used it with decent success for some problems (e.g. using high precision math only on problems that need it and using machine precision otherwise).

user
  • 7,123
  • 7
  • 48
  • 90
0

You could always try a conditional break when in debug mode, following is the link to the full answer as I answered someone else with a similar question:

Conditional Debug

This will allow you to simply pause execution when the conditions are met, it may not be an exception but it should help you nonetheless.

Community
  • 1
  • 1
Jamie Keeling
  • 9,806
  • 17
  • 65
  • 102