.- .
获取并设置浮点控制字。 _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_cw
和 sse2_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 |
要求
例程 | 必需的标头 |
---|---|
.- . | <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
另请参阅
数学和浮点支持
%>
.- .
_controlfp_s