繁体   English   中英

应该正确地循环

[英]should ldexp round correctly

我对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;
}

版画

g=9.88131e-324 e=1.4822e-323

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

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

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

g=1.4822e-323 e=1.4822e-323

这是我们对C / C ++编译器的期望,它承诺严格遵守IEEE-754。 这个问题被标记为CC++ ,我将在这里解决C99 ,因为这是我手头的标准。

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

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

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

在二元系统上, ldexp(x, exp)等同于scalbn(x, exp)

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

Scalb(y,N)返回y×2 N的积分值N而不计算2 N.

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

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

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

发生这种情况是因为在ldexp计算期间2.75被截断为2,这是因为在那个小的非规范化数字处,表示'.75'部分的位从可表示数字的末尾移开并消失。 无论这是一个错误还是设计行为都可以辩论。

当计算2.75*ldexp(1.0,-1074)时,正常的舍入发生,而2.75变为3。

编辑:ldexp应正确舍入,这是一个错误。

OP结果不符合C规范,因为规范没有定义计算的准确性。

OP结果可能已经失败了IEEE 754,但它取决于当时使用的舍入模式,该模式未发布。 然而,OP的报告2.75*ldexp(1.0,-1074)按预期工作,这意味着预期的舍入模式已经生效。

使用printf("%la",x)有助于清楚地看到接近double极限的情况。

我希望g能够“舍入到最近 - 与偶数相关”,结果为0x1.8p-1073 - 这确实发生在Windows上的gcc。

理想情况下, g的值为0x1.6p-1073

0x0.0p-1073 Zero
0x0.8p-1073 next higher double DBL_TRUE_MIN
0x1.0p-1073 next higher double
0x1.6p-1073 ideal `g` answer, but not available as a double
0x1.8p-1073 next higher double

公平地说,它可能是一个处理器错误 - 它以前发生过


参考

double g=ldexp(2.75,-1074);
printf("%la\n%la\n", 2.75,ldexp(2.75,-1074));
printf("%la\n%la\n", 3.0 ,ldexp(3.0 ,-1074));
double e=ldexp(3.0,-1074);
printf("%la\n%la\n", g,e);
printf("%la\n%la\n", 9.88131e-324, DBL_TRUE_MIN);
printf("g=%g e=%g \n",g,e);

0x1.6p+1
0x1.8p-1073
0x1.8p+1
0x1.8p-1073
0x1.8p-1073
0x1.8p-1073
0x1p-1073
0x1p-1074
g=1.4822e-323 e=1.4822e-323 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM