有没有自定义.NET如何处理浮点异常?

时间:2013-02-22 12:35:57

标签: .net delphi exception floating-point clr

显然,CLR通过忽略异常并返回默认值来处理浮点异常。例如,在浮点溢出的情况下,CLR返回+ Infinity,但不会引发异常。另一方面,Delphi默认会在溢出的情况下引发异常。这是由FPU异常标志控制的,你可以通过相应地设置异常标志使Delphi与CLR做同样的事情。一切都很好。

我有一个用Delphi编写的数值库,它期望溢出作为异常引发。然后它相应地处理这些边缘情况。如果没有引发异常,它就不知道该怎么做。现在,如果我在COM dll中使用此库并从托管代码调用该COM DLL,则不会将溢出作为异常引发,并且库返回不正确的结果。我通过以下代码包装对库的所有调用来解决这个问题:

var
  Mask : TFPUExceptionMask;
begin
  Mask := Math.SetExceptionMask([exDenormalized, exUnderflow, exPrecision]);
  try
    //do my calls to the library
  finally
    Math.SetException(Mask);
  end;

这似乎有效,但我现在有一个案例,我得到一个溢出,CLR似乎接管控制,Delphi永远不会得到一个EOverflow异常。它只是没有那么远。它进入一个溢出异常循环(浮点溢出而不是Delphi生成的EOverflows)并使应用程序崩溃。

解决这个问题的唯一方法是不使用上面的掩码,找出可能存在溢出的地方,并添加一些错误处理代码。这是一个例子:

f1 := Power(X, Y);
if f1 = Infinity then
  raise EOverflow.Create('Overflow');

这不太理想,因为我不太了解图书馆,无法猜测我可能会溢出的所有可能区域。但上述工作正常。

有人有这方面的经验吗?是否有可能告诉CLR退出FPU异常并让Delphi处理它们?顺便说一句,如果我从Excel VBA调用相同的COM DLL,有相同的掩码问题,但使用上面的第一个修复,即强制调用掩码,工作正常。这只是托管代码有问题。

所以这是一个例子:

我创建了一个带有单个COM对象的Delphi Active X库(DLL)。该对象有一个名为TestOverflow的方法,如下所示:

function TTestExceptions.TestOverflow : Double;
var
  Mask : TArithmeticExceptionMask;
begin
  Mask := GetExceptionMask;
  try
    Result := Power(600, 30000);
  except
    On EOverflow do
      Result := -1;
  end;
end;

然后我创建了三个客户端。一个用Delphi编写,一个用EXCEL VBA编写,一个用C#编写。每个客户都做同样的事情。创建COM对象的实例,并调用TestOverflow。

a)Delphi客户端

面具是[exDenormalized,exUnderflow,exPrecision]

抛出带有消息“浮点溢出”的异常$ C0000091,这被捕获为EOverflow异常,函数返回-1。

b)Excel客户端

面具是[exInvalidOp,exZeroDivide,exOverflow,exUnderflow,exPrecision]

不抛出异常,函数返回+ INF。

c)C#客户端

面具是[exInvalidOp,exZeroDivide,exOverflow,exUnderflow,exPrecision]

不抛出异常,函数返回+ INF。

然后我改变了函数来操作异常掩码:

function TTestExceptions.TestOverflow : Double;
var
  Mask : TArithmeticExceptionMask;
begin
  Mask := Math.SetExceptionMask([exDenormalized, exUnderflow, exPrecision]);
  try
    try
      Result := Power(600, 30000);
    except
      On EOverflow do
        Result := -1;
    end;
  finally
    Math.SetExceptionMask(Mask);
  end;
end;

这次我得到了:

a)Delphi客户端

抛出带有消息“浮点溢出”的异常$ C0000091,这被捕获为EOverflow异常,函数返回-1。

b)Excel客户端

抛出带有消息“浮点溢出”的异常$ C0000091,这被捕获为EOverflow异常,函数返回-1。

c)C#客户端

抛出了带有“浮点溢出”消息的异常$ C0000091,但执行没有继续,但在该行停止,似乎卡在该行,只是继续抛出相同的异常,直到它崩溃。

0 个答案:

没有答案