Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I force the C# compiler to throw an exception when any math operation produces 'NaN'?

Tags:

c#

exception

math

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.

like image 810
Trap Avatar asked Feb 12 '10 11:02

Trap


2 Answers

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.

like image 129
ChrisF Avatar answered Oct 24 '22 08:10

ChrisF


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.

like image 45
Michael Brandl Avatar answered Oct 24 '22 07:10

Michael Brandl