_control87, _controlfp, __control87_2

获取并设置浮点控制字。 _controlfp 有一个更安全的版本;请参阅 _controlfp_s

语法

unsigned int _control87(
   unsigned int new,
   unsigned int mask
);
unsigned int _controlfp(
   unsigned int new,
   unsigned int mask
);
int __control87_2(
   unsigned int new,
   unsigned int mask,
   unsigned int* x86_cw,
   unsigned int* sse2_cw
);

参数

new
新的控制字位值。

mask
要设置的新控制字位掩码。

x86_cw
使用 x87 浮点单元的控制字进行填充。 传入 0 (NULL) 来仅设置 SSE2 控制字。

sse2_cw
SSE 浮点单元的控制字。 传入 0 (NULL) 来仅设置 x87 控制字。

返回值

对于 _control87_controlfp 而言,返回值中的位表示浮点控制状态。 有关由 _control87 返回的位的完整定义,请参阅 FLOAT.H

对于 __control87_2,返回值为 1,表示成功。

备注

_control87 函数获取并设置浮点控制字。 浮点控制字允许程序根据平台更改精度、舍入和无穷模式。 还可使用 _control87 屏蔽或取消屏蔽浮点异常。 如果 mask 的值等于 0,则 _control87 获取浮点控制字。 如果 mask 为非零的值,则为控制字设置新值:对于 mask 中已设置的任何位(即等于 1),new 中的对应位被用于更新控制字。 即 fpcntrl = ((fpcntrl & ~mask) | (new & mask)),其中 fpcntrl 是浮点控制字。

注意

默认情况下,运行时库屏蔽所有浮点异常。

_controlfp_control87 的一个独立于平台的可移植版本,与 _control87 函数几乎完全相同。 如果代码面向多个平台,请使用 _controlfp_controlfp_s_control87_controlfp 之间的差异在于它们看待 DENORMAL 值的方式。 对于 x86、x64、ARM 和 ARM64 平台,_control87 可以设置和清除 DENORMAL OPERAND 异常掩码。 _controlfp 不修改 DENORMAL OPERAND 异常掩码。 此示例演示了差别:

_control87( _EM_INVALID, _MCW_EM );
// DENORMAL is unmasked by this call
_controlfp( _EM_INVALID, _MCW_EM );
// DENORMAL exception mask remains unchanged

控制字掩码和值表中显示了掩码常量 (mask) 和新控制值 (new) 的可能值。 请使用下面列出的可移植常量 (_MCW_EM_EM_INVALID,依此类推)作为这些函数的参数,而不是显式提供十六进制值。

Intel x86 派生的平台支持硬盘中的 DENORMAL 输入和输出值。 x86 行为是为了保留 DENORMAL 值。 支持 SSE2 的 ARM 和 ARM64 平台以及 x64 平台支持刷新 DENORMAL 操作数和结果,或将其强制为零。 _controlfp_control87 函数提供更改此行为的掩码。 下面的示例演示此掩码的使用。

_controlfp(_DN_SAVE, _MCW_DN);
// Denormal values preserved on ARM platforms and on x64 processors with
// SSE2 support. NOP on x86 platforms.
_controlfp(_DN_FLUSH, _MCW_DN);
// Denormal values flushed to zero by hardware on ARM platforms
// and x64 processors with SSE2 support. Ignored on other x86 platforms.

在 ARM 和 ARM64 平台上,将 _control87_controlfp 函数应用于 FPSCR 寄存器。 在 x64 平台上,仅存储在 MXCSR 寄存器中的 SSE2 控制字受到影响。 在 x86 平台上,_control87_controlfp 会对 x87 和 SSE2 的控制字(如果存在)产生影响。

函数 __control87_2 一起或单独控制 x87 和 SSE2 浮点单位。 若要影响这两个单元,请将这两个整数的地址传入 x86_cwsse2_cw。 如果仅想影响一个单元,则传入该参数的地址,但为另一个单元传入 0 (NULL)。 如果为其中一个参数传递了 0,则函数对该浮点单元没有影响。 当代码的一部分使用 x87 浮点单元,而另一部分使用 SSE2 浮点单元时,它很有用。

如果使用 __control87_2 为浮点控制字设置不同值,则 _control87_controlfp 可能无法返回表示这两个浮点单元状态的单个控制字。 在这种情况下,这些函数在返回的整数值中设置 EM_AMBIGUOUS 标志,以表示两个控制字之间的不一致性。 EM_AMBIGUOUS 标志是一条警告,指示所返回的控制字可能没有准确地表示两个浮点控制字的状态。

在 ARM、ARM64 和 x64 平台上,不支持更改无穷模式或浮点精度。 如果在 x64 平台上使用精度控制掩码,则函数引发断言并调用无效的参数处理程序,如参数验证中所述。

注意

在 ARM、ARM64 或 x64 平台上不支持 __control87_2。 如果使用 __control87_2 并为 ARM、ARM64 或 x64 平台编译程序,编译器将生成错误。

使用 /clr(公共语言运行时编译)进行编译时,这些函数将被忽略。 公共语言运行时 (CLR) 仅支持默认的浮点精度。

控制字掩码和值

对于 _MCW_EM 掩码,清除掩码将设置异常,这会允许硬盘异常;设置掩码可隐藏异常。 如果出现 _EM_UNDERFLOW_EM_OVERFLOW,则在执行下一步浮点指令之前,不会引发任何硬盘异常。 若要在 _EM_UNDERFLOW_EM_OVERFLOW 后立即生成硬件异常,请调用 FWAIT MASM 指令。

Mask 十六进制值 常数 十六进制值
_MCW_DN (非常规控制) 0x03000000 _DN_SAVE

_DN_FLUSH
0x00000000

0x01000000
_MCW_EM(中断异常掩码) 0x0008001F _EM_INVALID

_EM_DENORMAL

_EM_ZERODIVIDE

_EM_OVERFLOW

_EM_UNDERFLOW

_EM_INEXACT
0x00000010

0x00080000

0x00000008

0x00000004

0x00000002

0x00000001
_MCW_IC(无穷控制)

(在 ARM 或 x64 平台上不受支持。)
0x00040000 _IC_AFFINE

_IC_PROJECTIVE
0x00040000

0x00000000
_MCW_RC舍入控制) 0x00000300 _RC_CHOP

_RC_UP

_RC_DOWN

_RC_NEAR
0x00000300

0x00000200

0x00000100

0x00000000
_MCW_PC(精度控制)

(在 ARM 或 x64 平台上不受支持。)
0x00030000 _PC_24(24 位)

_PC_53(53 位)

_PC_64(64 位)
0x00020000

0x00010000

0x00000000

要求

例程 必需的标头
_control87, _controlfp, _control87_2 <float.h>

有关兼容性的详细信息,请参阅 兼容性

示例

// crt_cntrl87.c
// processor: x86
// compile by using: cl /W4 /arch:IA32 crt_cntrl87.c
// This program uses __control87_2 to output the x87 control
// word, set the precision to 24 bits, and reset the status to
// the default.

#include <stdio.h>
#include <float.h>
#pragma fenv_access (on)

int main( void )
{
    double a = 0.1;
    unsigned int control_word_x87 = 0;
    int result;

    // Show original x87 control word and do calculation.
    result = __control87_2(0, 0, &control_word_x87, 0 );
    printf( "Original: 0x%.8x\n", control_word_x87 );
    printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );

    // Set precision to 24 bits and recalculate.
    result = __control87_2(_PC_24, MCW_PC, &control_word_x87, 0 );
    printf( "24-bit:   0x%.8x\n", control_word_x87 );
    printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );

    // Restore default precision-control bits and recalculate.
    result = __control87_2( _CW_DEFAULT, MCW_PC, &control_word_x87, 0 );
    printf( "Default:  0x%.8x\n", control_word_x87 );
    printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );
}
Original: 0x0009001f
0.1 * 0.1 = 1.000000000000000e-02
24-bit:   0x000a001f
0.1 * 0.1 = 9.999999776482582e-03
Default:  0x0009001f
0.1 * 0.1 = 1.000000000000000e-02

另请参阅

数学和浮点支持
_clear87_clearfp
_status87_statusfp_statusfp2
_controlfp_s