【问题标题】:Delphi Berlin 10.1 Division by zero exception missingDelphi Berlin 10.1 除零异常丢失
【发布时间】:2023-03-17 02:34:01
【问题描述】:

我很惊讶得到除以零异常。如何找回?

Berlin 10.1 最近安装,新项目,

procedure TForm1.Button1Click(Sender: TObject);
var
  a: Double;
begin
  a := 5/0;                     // No exception
  ShowMessage(a.ToString);      // -> 'INF'
end;

【问题讨论】:

  • 在我的柏林副本上得到确认。好像也在东京:community.embarcadero.com/answers/…
  • @Jerry: 那是因为表达式是一个常量表达式,不是在运行时计算的。两个数(除数、除数)中的至少一个必须是变量才能导致异常。
  • 太棒了!编译器知道如何除以 0 :)
  • @Victoria:实际上,编译器可能也会将其留给 FPU,但在编译时会这样做,显然它会在这样做时掩盖(一些)异常。如果零除异常被屏蔽,则无限是有效结果。
  • 在西雅图我也能看到这种情况

标签: delphi exception delphi-10.1-berlin


【解决方案1】:
a := 5/0;

表达式5/0 在技术语言术语中是constant expression

常量表达式是编译器可以在不执行它所在的程序的情况下计算的表达式。常量表达式包括数字;字符串;真正的常数;枚举类型的值;特殊常量 True、False 和 nil;以及使用运算符、类型转换和集合构造函数专门从这些元素构建的表达式。

因此,此表达式由编译器计算,而不是在运行时计算。所以它的求值是由编译时规则决定的,不受运行时浮点单元异常掩码的影响。

这些规则规定正值除以零等于+INF,这是一个特殊的 IEEE754 值。如果您将表达式更改为至少有一个不是常量表达式的参数,那么它将在运行时计算,并引发除以零异常。

【讨论】:

    【解决方案2】:

    您可以使用数学单元中的 SetExceptionMask 函数控制触发哪些浮点异常:http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.Math.SetExceptionMask

    要禁用所有浮点异常,请使用:

    SetExceptionMask(exAllArithmeticExceptions);
    

    启用所有浮点异常使用:

    SetExceptionMask([]);
    

    另请注意,在您的示例代码中,编译器将在编译时确定值(因为表达式是常量),因此无论传递给 SetExceptionMask 的值如何,它都不会触发异常。要触发异常,您需要一个稍微复杂的示例,如下所示:

    program test;
    uses Math;
    var
      xx,yy: double;
    begin
    SetExceptionMask([]);
    xx := 1;
    yy := 0;
    halt(round(xx/yy));
    end.
    

    【讨论】:

    • 并且要启用除零异常,请执行以下操作:SetExceptionMask(GetExceptionMask - [exZeroDivide]);
    • 至少这个答案的第一部分与所提出的问题无关
    • @DavidHeffernan 在关于浮点异常未触发的讨论中,我认为提及 SetExceptionMask 是相关的。当然,这可能不是 OPs 代码中的原因,但这里发布的代码通常过于简化,实际代码可能使用了变量。
    • @VilleKrumlinde 公平评论,在这种情况下,发帖者可能会合理地遇到问题,并设法制定一个症状相似但根本原因不同的minimal reproducible example
    猜你喜欢
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 2016-10-15
    • 1970-01-01
    相关资源
    最近更新 更多