Oracle® Developer Studio 12.5:数值计算指南

退出打印视图

更新时间: 2016 年 6 月
 
 

3.5 C99 浮点环境函数

本节介绍了 C99 中的 <fenv.h> 浮点环境函数。在 Oracle Solaris 10 操作系统中,这些函数位于 libm 中。它们提供很多与 ieee_flags 函数相同的功能,但它们使用的 C 接口更普通;因为它们是由 C99 定义的,所以它们具有更高的可移植性。


注 -  为保持行为一致,请不要在同一程序中同时使用 libm 中的 C99 浮点环境函数和异常处理扩展以及 libsunmath 中的 ieee_flagsieee_handler 函数。

3.5.1 异常标志函数

fenv.h 文件为 5 个 IEEE 浮点异常标志中的每一个标志都定义了宏:FE_INEXACTFE_UNDERFLOWFE_OVERFLOWFE_DIVBYZEROFE_INVALID。此外,将宏 FE_ALL_EXCEPT 定义为所有 5 个标志宏进行按位“或”运算。在以下说明中,excepts 参数可以是 5 个标志宏中任何一个宏的按位“或”运算或者值 FE_ALL_EXCEPT。对于 fegetexceptflagfesetexceptflag 函数,flagp 参数必须是指向类型为 fexcept_t 的对象的指针。这种类型是在 fenv.h 中定义的。

C99 定义了下表中的异常标志函数:

表 28  C99 标准异常标志函数
函数
操作
feclearexcept(excepts)
清除指定的标志
fetestexcept(excepts)
返回指定标志的设置
feraiseexcept(excepts)
引发指定的异常
fegetexceptflag(flagp, excepts)
在 *flagp 中保存指定的标志
fesetexceptflag(flagp, excepts)
从 *flagp 中恢复指定的标志

feclearexcept 函数清除指定的标志。fetestexcept 函数返回与设置的 excepts 参数指定的标志子集对应的宏值的按位“或”运算结果。例如,如果当前设置的标志只有不精确、下溢和除以零,则以下指令将 i 设置为 FE_DIVBYZERO

i = fetestexcept(FE_INVALID | FE_DIVBYZERO);

如果启用任何指定异常的陷阱,则 feraiseexcept 函数会导致一个陷阱。否则,它只设置相应的标志。有关异常陷阱的更多信息,请参见异常和异常处理

fegetexceptflagfesetexceptflag 函数提供了一种简便的方法暂时保存某些标志的状态,并在以后恢复它们。特别地,fesetexceptflag 函数并不导致陷阱;它只恢复指定标志的值。

3.5.2 舍入控制

fenv.h 文件为 4 个 IEEE 舍入方向模式中的每一个模式定义了宏:FE_TONEARESTFE_UPWARD(向正无穷大舍入)、FE_DOWNWARD(向负无穷大舍入)和 FE_TOWARDZERO。C99 定义了两个函数以控制舍入方向模式:fesetround 将当前的舍入方向设置为其参数指定的方向(必须是以上 4 个宏之一),而 fegetround 返回对应于当前舍入方向的宏值。

在基于 x86 的系统上,fenv.h 文件为 3 个舍入精度模式中的每一个模式定义宏:FE_FLTPREC(单精度)、FE_DBLPREC(双精度)和 FE_LDBLPREC(扩展双精度)。虽然它们不是 C99 的一部分,但 x86 上的 libm 提供了两个函数来控制舍入精度模式:fesetprec 将当前的舍入精度设置为其参数指定的精度(必须是以上 3 个宏之一),而 fegetprec 返回对应于当前舍入精度的宏值。

3.5.3 环境函数

fenv.h 文件定义了数据类型 fenv_t,它表示整个浮点环境,包括异常标志、舍入控制模式、异常处理模式和(在 SPARC 上的)非标准模式。在以下说明中,envp 参数必须是指向类型为 fenv_t 的对象的指针。

C99 定义 4 个函数以处理浮点环境。libm 提供的一个附加函数在多线程程序中非常有用。下表概要介绍了这些函数:

表 29  libm 浮点环境函数
函数
操作
fegetenv(envp)
将环境保存在 *envp
fesetenv(envp)
*envp 中恢复环境
feholdexcept(envp)
将环境保存在 *envp 中,并建立不间断的模式
feupdateenv(envp)
*envp 中恢复环境并引发异常
fex_merge_flags(envp)
*envp 中的“或”异常标志

fegetenvfesetenv 函数分别用来保存和恢复浮点环境。fesetenv 的参数可以是指向以前通过调用 fegetenvfeholdexcept 保存的环境的指针,或者在 fenv.h 中定义的常量 FE_DFL_ENV。后者表示缺省环境,即清除所有异常标志、舍入到最接近的值以及在基于 x86 的系统上舍入到扩展双精度、不间断的异常处理模式(即禁用陷阱)以及禁用非标准的模式。

feholdexcept 函数会保存当前的环境,然后清除所有异常标志并为所有异常建立不间断的异常处理模式。feupdateenv 函数恢复保存的环境(可通过调用 fegetenvfeholdexcept 或常量 FE_DFL_ENV),然后引发在先前环境中设置其标志的异常。如果恢复的环境为其中的任何异常启用了陷阱,则会发生陷阱;否则,设置这些标志。可结合使用这两个函数,使子例程调用相对于异常为原子操作,如以下代码样例所示:

#include <fenv.h>
 
void myfunc(...) {
    fenv_t env;
 
    /* save the environment, clear flags, and disable traps */
    feholdexcept(&env);
    /* do a computation that may incur exceptions */
    ...
    /* check for spurious exceptions */
    if (fetestexcept(...)) {
        /* handle them appropriately and clear their flags */
        ...
        feclearexcept(...);
    }
    /* restore the environment and raise relevant exceptions */
    feupdateenv(&env);
}

fex_merge_flags 函数对当前环境和保存环境中的异常标志执行逻辑 OR 运算,而不调用任何陷阱。可以在多线程程序中使用此函数,在父线程中保存有关子线程中的计算引发的标志的信息。有关显示 fex_merge_flags 用法的示例,请参见示例