现在的位置: 首页 > 综合 > 正文

数学函数的异常捕获——Ada应用实例之十

2014年06月15日 ⁄ 综合 ⁄ 共 1700字 ⁄ 字号 评论关闭

  一帖子报告用C++语言编写了龙格——库塔方法解一个状态方程的程序,编译系统是Borland C++。程序运行过程中出现异常,错误信息是“floating point error”。

  笔者也用Borland C++试了一下,确实出错,但DEBUG状态下停在一条fprintf语句处,这里显然不是发生异常的地方。估计是浮点运算出错。但程序中有大量的算术运算和数学函数调用,很难通过单步运行来定位错误。

  首先怀疑数学函数调用。这可通过调用C++数学库中的函数_matherr来发现数学函数调用的异常。该函数的原型在<math.h>中:

  int _matherr( struct _exception *except );

  为了利用此函数,只需在程序中定义一个这样的函数,例如:

int _matherr(struct _exception *except)

{

const char* errorString[] =

{

    "", /*异常类型从1开始编号,因此[0]留空*/

"_DOMAIN(参数域错误)",

"_SING(参数奇异)",

"_OVERFLOW(上溢)",

"_UNDERFLOW(下溢)"

"_TLOSS(丢失全部精度)",

"_PLOSS(丢失部分精度)"

};

      printf("出现异常的数学函数名称:%s/n",except->name);

      printf("该函数的输入参数:参数1=%g, 参数2(如果有)=%g/n",except->arg1,except->arg2);

      printf("异常类型:%s/n",errorString[except->type]);

      printf("该函数的返回值:%g/n",except->retval);

      return 1;

}

 

  然后在这个函数中设了一个断点。运行时果然进入了这个函数,原来是 sqrt的参数是负数,所以出现异常。

  如果用Ada编程,那么事情就简单多了。设有以下程序:

with Ada.Exceptions; use Ada.Exceptions;

with Ada.Numerics.Elementary_Functions;

use Ada.Numerics.Elementary_Functions;

with Ada.Text_IO; use Ada.Text_IO;

 

procedure Main is

   r : Float;

begin

   r := Sqrt (-1.0);

   exception

      when Event : others =>

         Put ("Unexpected exception:");

         Put_Line (Exception_Name (Event));

         Put_Line (Exception_Message (Event));

end Main;

 

  上述程序运行后将输出如下信息:

Unexpected exception:ADA.NUMERICS.ARGUMENT_ERROR

Exception name: ADA.NUMERICS.ARGUMENT_ERROR

Message: a-ngelfu.adb:933 instantiated at a-nuelfu.ads:18

 

  最后一行指出异常发生的源文件位置。文件a-ngelfu.adb是数学库的源文件,在933行附近的代码是:

   function Sqrt (X : Float_Type'Base) return Float_Type'Base is

   begin

      if X < 0.0 then

         raise Argument_Error;  -- 933

 

      --  Special case Sqrt (0.0) to preserve possible minus sign per IEEE

 

      elsif X = 0.0 then

         return X;

 

      end if;

 

      return Float_Type'Base (Aux.Sqrt (Double (X)));

   end Sqrt;

 

  由此可见,异常原因是sqrt的输入参数是负数。

抱歉!评论已关闭.