主页C++ Builder 资料C++ Builder 参考手册cfloat 浮点数_control87, _controlfp
C++ Builder 串口控件
C++ Builder 编程技巧
C++ Builder 操作指南
C++ Builder 参考手册
基础知识
cfloat 浮点数
 • 浮点数类型
 • 浮点数异常处理
 • _finite, _finitel
 • _isinf, _isinfl
 • _isnan, _isnanl
 • _fpclass, _fpclassl
 • _chgsign, _chgsignl
 • _copysign, _copysignl
 • _logb, _logbl
 • _scalb, _scalbl
 • _nextafter, _nextafterl
 • _clear87, _clearfp
 • _control87, _controlfp
 • _status87, _statusfp
 • _fpreset
cmath 数学函数
cstdlib 标准库函数
System 字符串
System 日期和时间
System.Math.hpp 数学函数
其他数据类型
VCL 基础类
VCL 应用程序
Pictures 图片
Graphics 绘图
Additional 控件
System 控件
A ~ Z 字母顺序排列的目录
网友留言/技术支持
_control87, _controlfp - 改变 x87 (x86 的浮点内核) 的数据处理方式,或屏蔽和启用浮点异常

_control87, _controlfp:改变 x87 (x86 的浮点内核) 的数据处理方式,或屏蔽和启用浮点异常

函数原型:

unsigned int _control87(unsigned int newcw, unsigned int mask);
#define _controlfp(a, b) _control87((a), ((b)& (~EM_DENORMAL)))

头文件:

#include <cfloat>

命名空间:

std

参数:

newcw:新的控制字
mask:控制字掩码,只有掩码等于 1 的二进制位对应的新控制字二进制位写入 x87 控制字

异常中断控制    
MCW_EM 0x003f 异常中断掩码 (interrupt Exception Masks),
控制字的这些位如果等于 0 产生对应的异常中断 (抛出异常) 或等于 1 得到 ± 0、± NAN、± INF 等计算结果
EM_INVALID 0x0001 不合理的运算 (invalid),例如 0.0 除以 0.0 就是不合理的运算,无法计算出结果。
控制字这一位等于 0:抛出异常 EInvalidOp;等于 1:计算结果为 ± NAN
EM_DENORMAL 0x0002 次正常 (denormal):有效数字向下溢出一部分,可以使用精度不足的浮点数来表示运算结果【
控制字这一位等于 0:抛出异常 EInvalidOp;等于 1:计算结果用 “次正常” 的浮点数表示
EM_ZERODIVIDE 0x0004 被零除 (zero divide),不等于零的数值除以零。
控制字这一位等于 0:抛出异常 EZeroDivide;等于 1:计算结果为 ± INF
EM_OVERFLOW 0x0008 向上溢出 (overflow),绝对值太大,超过了浮点数能够表达的范围【
控制字这一位等于 0:抛出异常 EOverflow;等于 1:计算结果等于 ± HUGE_VAL
EM_UNDERFLOW 0x0010 向下溢出 (underflow),绝对值太小,超过了浮点数能够表达的范围【
控制字这一位等于 0:抛出异常 EUnderflow;等于 1:计算结果等于 ± 0
EM_INEXACT 0x0020 降低精度 (inexact (precision)),例如把 double 赋值给 float,降低了精度【
控制字这一位等于 0:抛出异常 EInvalidOp;等于 1:结果为降低精度的值
无穷大控制    
MCW_IC 0x1000 无穷大控制掩码 (Infinity Control)
IC_AFFINE 0x1000 仿射 (affine) 新的 x87 (从 387 开始) 采取仿射无穷大,即使用负无穷大和正无穷大
IC_PROJECTIVE 0x0000 投影 (projective) 早期的浮点数内核 287 使用投影无穷大,即无符号无穷大,正无穷大和负无穷大相等
舍入控制    
MCW_RC 0x0c00 舍入控制掩码 (Rounding Control)
RC_CHOP 0x0c00 舍弃 (chop)
RC_UP 0x0800 向上 (up)
RC_DOWN 0x0400 向下 (down)
RC_NEAR 0x0000 接近 (near),现在的 x87 默认采用接近值,即四舍五入
精度控制    
MCW_PC 0x0300 精度控制掩码 (Precision Control)
PC_24 0x0000 24 bits
PC_53 0x0200 53 bits
PC_64 0x0300 64 bits,现在的 x87 默认采用 64 bits 精度

注:溢出、向上溢出、向下溢出、次正常、降低精度

浮点数向上和向下超出范围是有区别的:
• 向上 (向左方向) 只要有一位超过范围了,是最高位丢失,数据完全失去意义了,就是向上溢出 (overflow)
• 向下 (向右方向) 如果有超过范围的数据,是低位丢失,相当于降低了精度,属于次正常 (denormal) 数据,一直到最高位也丢失了,数据才失去意义,这时候才算是向下溢出 (underflow)
• 在需要保证精度的情况下,次正常就属于错误数据了,如果精度要求不高的情况下,次正常数据还可以用,所以可以设定次正常是否抛出异常

最大值     9 9 9 9 9 9 0 0 0 0 0 0 . 0                                     假定浮点数表示的最大值
最小值                           0 . 0 0 0 0 0 0 9 9 9 9 9 9               假定浮点数表示的最小值
向上溢出   1 2 3 4 5 6 0 0 0 0 0 0 0 . 0                                     最高位丢失,数据的值失去意义,向上溢出
正常值     1 2 3 4 5 6 0 0 0 0 0 0 . 0                                     保证精度的正常值
正常值                     1 2 3 4 . 5 6                                   保证精度的正常值
降低精度                     1 2 3 4 . 5 6                                   正常值范围内丢弃低位,例如双精度值赋值给单精度
正常值                           0 . 0 0 0 0 0 0 1 2 3 4 5 6               保证精度的正常值
次正常                           0 . 0 0 0 0 0 0 0 1 2 3 4 5 6             低位丢失,降低了精度,如果精度要求不高还可以用
次正常                           0 . 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6     低位丢失,降低了精度,如果精度要求不高还可以用
向下溢出                           0 . 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6   最高位丢失,数据的值失去意义,向下溢出

返回值:

新的浮点数控制字

例1:次正常 (denormal) 抛出异常的例子

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  UnicodeString s;
  try
   {
     // 保存原来的控制字,新控制字为次正常抛出异常
     unsigned int uOldC87 = std::_control87(~EM_DENORMAL, MCW_EM);
     try
      {
        double x = 2.1e-308;
        double y = x / 2.0;
        s.cat_sprintf(L"%g\r\n", y);
      }
     __finally
      {
        std::_control87(uOldC87, MCW_EM); // 恢复原来的控制字
      }
   }
  catch(Exception &E)
   {
     s += L"捕获异常: " + E.ClassName() + L"\r\n";
     s += L"错误信息: " + E.Message + L"\r\n";
   }
  Memo1->Lines->Text = s;
}

例2:次正常 (denormal) 不抛出异常,得到精度不足的值的例子

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  UnicodeString s;
  try
   {
     // 保存原来的控制字,新控制字为次正常得到精度不足的计算结果
     unsigned int uOldC87 = std::_control87(MCW_EM, MCW_EM);
     try
      {
        double x = 2.1e-308;
        double y = x / 2.0;
        s.cat_sprintf(L"%g\r\n", y);
      }
     __finally
      {
        std::_control87(uOldC87, MCW_EM); // 恢复原来的控制字
      }
   }
  catch(Exception &E)
   {
     s += L"捕获异常: " + E.ClassName() + L"\r\n";
     s += L"错误信息: " + E.Message + L"\r\n";
   }
  Memo1->Lines->Text = s;
}

兼容性:

clang64 不支持这一组函数,其中:
• “异常中断控制” 可以使用 GetExceptionMask 和 SetExceptionMask 函数;
• “舍入控制” 可以使用 GetRoundMode 和 SetRoundMode 函数;
• “精度控制” 可以使用 GetPrecisionMode 和 SetPrecisionMode 函数。

函数 \ C++ Builder 编译器 bcc32 clang32 clang64
_control87  
_controlfp  

相关链接:

_finite_isinf_isnan_fpclass_control87SetExceptionMask_matherr浮点数异常处理

◤上一页:_clear87, _clearfp下一页:_status87, _statusfp

C++ 爱好者 -- Victor Chen 的个人网站 www.cppfans.com 辽ICP备11016859号