是否可以在 C++ 中下溢浮点加法?
Is it possible to underflow a floating point addition in C++?
我正在查看英特尔处理器手册,第 2A 卷,第 3.266-3.268 页,它指出 FADD 操作可能会产生 #U(下溢)异常。
原因是结果太小,无法在 DST 中正确表示。
我想知道在使用本机数据类型(float、double、long double)的 C++ 上加法下溢是否可能,或者数据类型的语言包装是否使加法操作在下溢方面是安全的。
如果将彼此非常接近的正数和负数相加,会产生 denormal, then the underflow flag is set (if underflow exception is not masked). Link to intel article denormals and underflow。
示例代码(使用微软编译器):
double a,b,c;
a = 2.2250738585072019e-308;
b = -2.2250738585072014e-308;
c = a + b; /* c is denormal */
printf("%28.16le %016llx\n", a, a);
printf("%28.16le %016llx\n", b, b);
printf("%28.16le %016llx\n", c, c);
if ( std::fpclassify( c ) == FP_SUBNORMAL ) printf("c is DENORMAL");
启用(取消屏蔽)下溢异常(Microsoft 编译器):
short fcw; /* floating point control word - 16 bit */
/* enable underflow exception */
__asm{
fnstcw fcw
and fcw,0ffefh
fldcw fcw
}
当计算结果是非正规(次正规)数时,会发生下溢情况。这正式称为 gradual underflow(与产生零相反)。因此,几乎任意两个非正规数相加,只要结果也是非正规数,就会发生下溢。例如:
pow(2.0, -1074.0) + pow(2.0, -1073.0)
这里所有的操作数都是double类型。
英特尔当然指的是逐渐下溢。然而考虑到突然下溢,那么仅使用加法and/or减法是不可能的。
我正在查看英特尔处理器手册,第 2A 卷,第 3.266-3.268 页,它指出 FADD 操作可能会产生 #U(下溢)异常。 原因是结果太小,无法在 DST 中正确表示。
我想知道在使用本机数据类型(float、double、long double)的 C++ 上加法下溢是否可能,或者数据类型的语言包装是否使加法操作在下溢方面是安全的。
如果将彼此非常接近的正数和负数相加,会产生 denormal, then the underflow flag is set (if underflow exception is not masked). Link to intel article denormals and underflow。
示例代码(使用微软编译器):
double a,b,c;
a = 2.2250738585072019e-308;
b = -2.2250738585072014e-308;
c = a + b; /* c is denormal */
printf("%28.16le %016llx\n", a, a);
printf("%28.16le %016llx\n", b, b);
printf("%28.16le %016llx\n", c, c);
if ( std::fpclassify( c ) == FP_SUBNORMAL ) printf("c is DENORMAL");
启用(取消屏蔽)下溢异常(Microsoft 编译器):
short fcw; /* floating point control word - 16 bit */
/* enable underflow exception */
__asm{
fnstcw fcw
and fcw,0ffefh
fldcw fcw
}
当计算结果是非正规(次正规)数时,会发生下溢情况。这正式称为 gradual underflow(与产生零相反)。因此,几乎任意两个非正规数相加,只要结果也是非正规数,就会发生下溢。例如:
pow(2.0, -1074.0) + pow(2.0, -1073.0)
这里所有的操作数都是double类型。
英特尔当然指的是逐渐下溢。然而考虑到突然下溢,那么仅使用加法and/or减法是不可能的。