在编写高精度浮点运算程序时,需要对浮点环境进行控制并捕获浮点环境异常。cfenv头文件定义了对浮点环境控制及异常相关的函数和宏。
注记
FENV_ACCESS
#pragma STDC FENV_ACCESS on //设置该参数表示可以访问浮点运算异常的状态值
#pragma STDC FENV_ACCESS off //设置该参数表示禁止访问浮点运算异常的状态值
浮点数异常处理
函数
/* 清除EXCEPTS表示的异常状态 */
int feclearexcept (int __excepts);
/* 产生由EXCEPTS表示的异常 */
int feraiseexcept (int __excepts) ;
/* 将实现定义的异常标志EXCEPTS保存到FLAGP所指的对象中 */
int fegetexceptflag (fexcept_t *__flagp, int __excepts) ;
/* 根把EXCEPTS异常标志设置为FLAGP所指对象中的值 */
int fesetexceptflag (__const fexcept_t *__flagp, int __excepts) ;
/* 确定EXCEPTS指示的各个异常中有哪个异常子集被设置了 */
int fetestexcept (int __excepts) ;
宏(int类型)
FE_INEXACT 精度丢失
FE_DIVBYZERO 除数为0
FE_UNDERFLOW 结果向下溢出
FE_OVERFLOW 结果向上溢出
FE_INVALID 无效的运算
FE_ALL_EXCEPT 所有被支持的异常的按位或
示例1
#include <stdio.h> /* printf */
#include <fenv.h> /* fegetround, FE_* */
#include <math.h> /* rint */
void show_all_except(void);
int main ()
{
show_all_except();
double d = 1e-40;
float f;
f = d;//这种精度丢失在编译过程中编译器编译不会提示,运行也没有问题
show_all_except();
return 0;
}
void show_all_except(void)
{
//设置该参数表示可以访问浮点运算异常的状态值
#pragma STDC FENV_ACCESS ON
//获取所有可能的异常
int res = fetestexcept(FE_ALL_EXCEPT);
printf( "Status: " );
if(res & FE_INEXACT)//判断是否有精度损失的异常
{
printf( " inexact ");
}
if(res & FE_UNDERFLOW)//判断是否有下溢
{
printf( " underflow ");
}
if(res & FE_OVERFLOW)//判断是否有上溢
{
printf( " overflow ");
}
if(res & FE_DIVBYZERO)//判断是否有被0除
{
printf( " zero-divide ");
}
if(res & FE_INVALID)//判断是否有不合法的浮点运算
{
printf( " invalid ");
}
printf( " \n ");
}
运行结果
Status:
Status: inexact underflow
高精度编程时,可以通过这些函数检查是否存在异常,并进行相应处理。
舍入控制
函数
宏(int类型)/* 获得当前的舍入方向,表示为一个舍入方向宏值 */
int fegetround (void) ;
/* 设置舍入方向,成功时返回0 */
int fesetround (int __rounding_direction) ;
FE_TONEAREST 最近舍入
FE_UPWARD 向正无穷大(+Inf)舍入
FE_DOWNWARD 向负无穷大(-Inf)舍入
FE_TOWARDZERO 向0舍入
示例2
#include <stdio.h> /* printf */
#include <fenv.h> /* fegetround, FE_* */
#include <math.h> /* rint */
void printfRounding();
int main ()
{
printfRounding();
printf ( "rint (2.49) = %.1f\n", rint(2.49) );
printf ( "rint (3.50) = %.1f\n", rint(3.50) );
fesetround(FE_TOWARDZERO);
printfRounding();
printf ( "rint (2.49) = %.1f\n", rint(2.49) );
printf ( "rint (3.50) = %.1f\n", rint(3.50) );
return 0;
}
void printfRounding()
{
printf ("now rounding using: ");
switch (fegetround()) {
case FE_DOWNWARD: printf ("downward"); break;
case FE_TONEAREST: printf ("to-nearest"); break;
case FE_TOWARDZERO: printf ("toward-zero"); break;
case FE_UPWARD: printf ("upward"); break;
default: printf ("unknown");
}
printf("\n");
}
运行结果:
now rounding using: to-nearest
rint (2.49) = 2.0
rint (3.50) = 4.0
now rounding using: toward-zero
rint (2.49) = 2.0
rint (3.50) = 3.0
浮点数环境
函数
/* 获取当前的浮点数环境,并保存在ENVP所指的对象中 */
int fegetenv (fenv_t *__envp) ;
/* 设置浮点数环境 */
int fesetenv (__const fenv_t *__envp);
/* 将当前浮点数环境保存到ENVP所指对象中,清除异常标志,然后安装一个无异常的浮点数环境 */
int feholdexcept (fenv_t *__envp) ;
/*没整明白*/int feupdateenv (__const fenv_t *__envp) ;
类型
fenv_t 表示浮点数环境的类型
fexcept_t 表示浮点数异常标志(这个标志保存了浮点数的状态)的类型
宏(fenv_t *指针类型)
示例3:(本示例中用到了两个打印函数分别在示例1、示例2中定义)FE_DFL_ENV 表示浮点数环境的缺省值(用于需要fenv_t参数的函数中)
#include <stdio.h> /* printf */
#include <fenv.h> /* fegetround, FE_* */
#include <math.h> /* rint */
void printfRounding();
void show_all_except(void);
int main ()
{
fenv_t fe;
printfRounding();//打印当前Rounding规则
show_all_except();//打印当前异常状态
fesetround(FE_TOWARDZERO);//设置Rounding规则为向0靠近
feraiseexcept(FE_INEXACT);//注册一个精度丢失异常
printfRounding();//重新打印当前Rounding规则
show_all_except();//重新打印当前异常状态
fegetenv(&fe);//获取当前浮点环境
fesetenv(FE_DFL_ENV);//设置浮点环境为默认值
printfRounding();//重新打印当前Rounding规则
show_all_except();//重新打印当前异常状态
fesetenv(&fe);//设置浮点环境为上次保存的浮点环境
printfRounding();//重新打印当前Rounding规则
show_all_except();//重新打印当前异常状态
feraiseexcept(FE_OVERFLOW);//注册一个结果向上溢出异常
feholdexcept(&fe);//保存当前浮点环境,并清除所有异常
printfRounding();//重新打印当前Rounding规则
show_all_except();//重新打印当前异常状态
fesetenv(&fe);//设置浮点环境为上次保存的浮点环境
printfRounding();//重新打印当前Rounding规则
show_all_except();//重新打印当前异常状态
return 0;
}
运行结果
now rounding using: to-nearest
Status:
now rounding using: toward-zero
Status: inexact
now rounding using: to-nearest
Status:
now rounding using: toward-zero
Status: inexact
now rounding using: toward-zero
Status:
now rounding using: toward-zero
Status: inexact overflow