不同的平台在C中有不同的双精度吗?

时间:2018-02-05 07:07:22

标签: c

C代码

#include <stdio.h>

int main(int argc, char *argv[]) {
    double x = 1.0/3.0;
    printf("%.32f\n", x);
    return 0;
}

在Windows Server 2008 R2上,我使用MSVC 2013编译并运行代码。输出为:

0.33333333333333331000000000000000

在macOS High Sierra上,我使用Apple LLVM 9.0.0版(clang-900.0.39.2)编译并运行相同的代码。输出是:

0.33333333333333331482961625624739

ideone.com上运行相同的代码会产生与macOS上相同的结果。

我知道双精度浮点格式只有大约15或16个有效十进制数字。该数字保留了macOS平台上64位二进制值1/3(作为Wikipedia's explanation)的精确十进制表示,但为什么它在Windows平台上被“截断”?

5 个答案:

答案 0 :(得分:4)

根据C标准,以下行为是implementation-defined

  
      
  1. 浮点运算(+-*/)以及<math.h>和{{中的库函数的准确性返回浮点结果的1}}是实现定义的,<complex.h><stdio.h>中库函数执行的浮点内部表示和字符串表示之间转换的准确性。和<stdlib.h>。实施可能表明准确性未知。
  2.   

答案 1 :(得分:2)

MSVC docs开始,因为MSVC符合IEEE double 最多 16 有效数字。

the docs也声明默认情况下/fp标志设置为精确:

  

使用/ fp:精确地在x86处理器上,编译器执行舍入   float类型的变量到赋值和的正确精度   强制转换以及何时将参数传递给函数。这四舍五入   保证数据不会保留任何大于的意义   其类型的能力。

因此,当你将它传递给printf时,你将它变为圆形,得到那些零。据我所知,尾随1是噪音,不应该在那里(它是数字17,我算了)。

此行为是MSVC特定的,您可以在我链接的文档中详细了解它,以查看其他编译器需要哪些标记。

答案 2 :(得分:1)

根据coding-guidelines

  

696 当double被降级为float时,long double被降级为double或float,或者一个值以更高的精度表示   语义类型所需的范围(见6.3.1.8)是明确的   如果转换为它的语义类型(包括它自己的类型)   转换后的值可以用新类型表示   没有改变。

     

697 如果转换的值在可以表示但无法准确表示的值范围内,则结果为   选择的最接近的较高或最接近的较低的可表示值   以实现定义的方式。

     

698 如果转换的值超出了可以表示的值范围,则行为未定义。

答案 3 :(得分:1)

是的,不同的实现可能具有不同特征的double类型,但这实际上并不是您在此处看到的行为的原因。在这种情况下,原因是用于将浮点值转换为十进制的Windows例程不会产生IEEE 754中定义的正确舍入结果(它们在有限数量的数字之后“放弃”),而macOS例程执行产生正确的舍入结果(事实上,如果允许产生足够的数字,则产生确切的结果)。

答案 4 :(得分:0)

简短的回答是:是的,不同的平台表现不同。

来自Intel

  

Intel Xeon处理器E5-2600 V2产品系列支持半精度(16位)浮点数据类型。与单精度(32位)浮点数据格式相比,半精度浮点数据类型提供了2倍的紧凑数据表示,但牺牲了数据范围和精度。特别是,当32位浮点数据不适合L1缓存时,半浮点数可能比32位浮点数提供更好的性能。

我无法访问Xeon计算机来测试这个,但我希望你最终得到的double不是真正的double,因为使用了“更快的浮点,但精度更低的“CPU指令。

英特尔酷睿处理器的“i”系列没有半宽快速浮点精度,因此不会截断结果。

以下是英特尔网站上half-precision format in Xeon的更多信息。