应该正确地循环

aka*_*ice 6 c c++ floating-point visual-studio

我对MSVC ldexp行为感到有些惊讶(它发生在Visual Studio 2013中,但也适用于所有旧版本,至少到2003年......).

例如:

#include <math.h>
#include <stdio.h>
int main()
{
    double g=ldexp(2.75,-1074);
    double e=ldexp(3.0,-1074);

    printf("g=%g e=%g \n",g,e);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

版画

g=9.88131e-324 e=1.4822e-323
Run Code Online (Sandbox Code Playgroud)

第一个g是奇怪的圆形...
它是2.75*fmin_denormalized,所以我绝对期望第二个结果e.
如果我评价2.75*ldexp(1.0,-1074)我正确得到与e相同的值.

我的期望是否太高,或者微软是否未能遵守某些标准?

nju*_*ffa 5

虽然问题没有明确说明这一点,但我认为提问者预期的输出是:

g=1.4822e-323 e=1.4822e-323
Run Code Online (Sandbox Code Playgroud)

这是我们对C/C++编译器的期望,它承诺严格遵守IEEE-754.问题是标签都CC++我将讨论C99在这里,因为这是我手上的标准.

在附件F中,描述了IEC 60559浮点运算(其中IEC 60559基本上是IEEE-754的另一个名称),该C99标准规定:

定义的实现__STDC_IEC_559__应符合本附件中的规范.[...]这些scalbnscalbln 功能<math.h>提供了IEC 60559附录中推荐的scalb功能.

在该附件中,F.9.3.6节规定:

在二进制系统上,ldexp(x, exp)相当于scalbn(x, exp).

C99标准引用的附录是1985年版IEEE-754的附录,其中我们发现scalb函数定义如下:

Scalb(Y,N)返回y×2 Ñ为积分值对应N不用计算2 Ñ.

scalb定义为乘以2的幂,乘法必须根据标准根据当前的舍入模式正确舍入.因此,如果编译器定义,符合标准的C99编译器ldexp()必须返回正确舍入的结果.在没有库调用设置舍入模式的情况下,默认舍入模式"舍入到最接近或甚至"是有效的.__STDC_IEC_559__

我无法访问MSVC 2013,因此我不知道它是否定义了该符号.这甚至可能取决于编译器标志设置,例如/fp:strict.

在追踪我的C++ 11标准副本之后,我找不到任何__STDC_IEC_559__关于IEEE-754绑定的参考或任何语言.根据这个问题的答案,是因为参考C99标准包含了这种支持.