当任何数学运算产生'NaN'时,如何强制C#编译器抛出异常?

Tra*_*rap 5 c# math exception

我最近编写的程序中的一些数学函数返回了不可接受的值,例如NaN(可能是因为没有检查某些函数的输入参数).问题在于,很难找到哪些函数传递了错误的值.这会导致错误在整个代码中传播,并使程序在几分钟或几小时后崩溃,如果有的话.

我想知道是否有办法在任何操作产生NaN值的时候捕获这些错误操作(与一些C/C++编译器抛出的'DivisionByZero异常'几乎相同,如果我记得的话).

提前致谢.

PD:如果需要,请随时重新标记我的问题.

Chr*_*isF 9

在没有看到你的代码的情况下,这个答案必然是模糊的,但是这样做的一种方法是检查你的函数的输出,如果它是"NaN"引发和异常:

if (double.IsNaN(result))
{
    throw new ArithmeticException();
}
Run Code Online (Sandbox Code Playgroud)

但有关异常的更多细节.

UPDATE

要捕获抛出特定异常的位置,您可以(暂时)在调试器中抛出异常时中断.

选择Debug> Exceptions,然后展开树以选择Common Language Runtime Exceptions> System> System.ArithmeticException并选中"Thrown"选项.

这样做的问题在于它会在抛出的任何地方破坏,而不仅仅是在你的代码中.将显式代码置于足够低的水平可以解决这个问题.


小智 7

这个问题似乎有点老了,但是因为我偶然发现了同样的问题:Alexander Torstling的回答以及下面的评论对我来说非常有用.

有趣的是,即使c#没有提供它自己的方式来启用浮点异常,它仍然可以捕获它们(对于c ++,你需要先进行转换).

C#代码在这里:

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());
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我得到的异常是{"算术运算中的溢出或下溢."} System.Exception {System.ArithmeticException}

不知道为什么调试器会抱怨_control87的签名; 谁可以改进呢?不过,"继续"对我来说很好.


Ale*_*ing 5

我不知道这是否适用于CLR,但您可以使用_controlfp_s from来触发浮点异常:

unsigned int _oldState;
errno_t err = _controlfp_s(&oldState, 0, MCW_EM);
assert(!err);
Run Code Online (Sandbox Code Playgroud)

重置:

errno_t err = _controlfp_s(0, _oldState, MCW_EM);
assert(!err);
Run Code Online (Sandbox Code Playgroud)