我最近编写的程序中的一些数学函数返回了不可接受的值,例如NaN(可能是因为没有检查某些函数的输入参数).问题在于,很难找到哪些函数传递了错误的值.这会导致错误在整个代码中传播,并使程序在几分钟或几小时后崩溃,如果有的话.
我想知道是否有办法在任何操作产生NaN值的时候捕获这些错误操作(与一些C/C++编译器抛出的'DivisionByZero异常'几乎相同,如果我记得的话).
提前致谢.
PD:如果需要,请随时重新标记我的问题.
在没有看到你的代码的情况下,这个答案必然是模糊的,但是这样做的一种方法是检查你的函数的输出,如果它是"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的签名; 谁可以改进呢?不过,"继续"对我来说很好.
我不知道这是否适用于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)