为什么最右边的数字不是零(C / Linux)?

时间:2012-12-07 09:08:28

标签: c floating-point

如果打印的浮点数精度高于存储在存储器中的浮点数,那么它们不应该是额外的零点吗?我的代码是这样的:

double z[2*N]="0";
...
for( n=1; n<=2*N; n++) {
  fprintf( u1, "%.25g", z[n-1]);
  fputc( n<2*N ? ',' : '\n', u1);
}

正在创建这样的输出:

0,0.7071067811865474617150085,....

一个浮点数应该只有17个小数位(右边?不是53位到17个小数位)。如果是这样的话,那么第18,19 ...... 25位应该有零。请注意,在上面的输出中,它们的数字不是0。

我误解了什么吗?如果是这样,是什么?

4 个答案:

答案 0 :(得分:7)

不,53位意味着17个小数位是你可以信任的,但是因为我们使用的base-10表示法与存储double的基数不同(二进制),后面的数字只是因为1/2 ^ 53不完全是1/10 ^ n,即

1/2 ^ 53 = .0000000000000001110223024625156540423631668090820312500000000

答案 1 :(得分:4)

您的实现打印的字符串显示示例中double的确切值,C标准允许这样做,如下所示。

首先,我们应该了解浮点对象代表什么。 C标准做得不好,但是,假设您的实现使用IEEE 754浮点标准,正常的浮点对象表示完全( - 1) s •2 e •(1 + f)对于某些符号位s(0或1),指数e(在特定类型的范围内,-1022到1023为double)和分数f(同样在范围内,小数点后的52位为双倍)。许多人使用该对象近似附近的值,但是,根据标准,该对象仅表示它定义的一个值。

您显示的值,0.7071067811865474617150085,可以完全表示为double(符号位0,指数-1和小数位[十六进制] .6a09e667f3bcc 16 )。重要的是要理解双精度,这个值恰好代表该值;它不代表附近的值,例如0.707106781186547461715。

现在我们知道传递给fprintf的值,我们可以考虑C标准对此的说法。首先,C标准定义了一个名为DECIMAL_DIG的常量。 C 2011 5.2.4.2.2 11将此值定义为十进制数字的数量,使得最宽支持类型中的任何浮点数可以舍入到那么多十进制数字,然后再返回而不更改值。传递给fprintf的精度为25,可能大于系统上DECIMAL_DIG的值。

在C 2011 7.21.6.1 13中,标准说“如果有效十进制数字的数量大于DECIMAL_DIG但源数值可以用DECIMAL_DIG数字准确表示,那么结果应该是具有尾随零的精确表示。否则,源值由两个相邻的十进制串L&lt; U,两者都有DECIMAL_DIG有效数字;结果十进制字符串D的值应该满足L≤D≤U,并额外规定误差应该对当前的舍入方向有正确的符号。“

这个措辞允许编译器有一些摆动空间。目的是结果必须足够准确,以便可以将其转换回原始的双重而没有错误。它可能更准确,并且一些C实现将产生完全正确的值,这是允许的,因为它满足上面的段落。

顺便提一下,您显示的值不是最接近sqrt(2)/ 2的两倍。该值为+ 0x1.6A09E667F3BCDp-1 = 0.70710678118654757273731092936941422522068023681640625。

答案 2 :(得分:0)

有足够的精确度来表示double precision floating point中的0.7071067811865474617150085。 64位输出实际上是3FE6A09E667F3BCC

用于评估数字的公式是取幂,因此您不能说53位将占用17小数位。

编辑: 在另一个实例的维基文章中查看下面的示例:

 0.333333333333333314829616256247390992939472198486328125
=2^(−54) × 15 5555 5555 5555 base16
=2^(−2) × (15 5555 5555 5555 base16 × 2^(−52) )

答案 3 :(得分:0)

你要求浮动,但在你的代码中出现双倍。

无论如何,float或double都不会始终具有相同的小数位数。根据IEEE 754,Float为浮点表示分配了32位(4字节)。

来自Wikipedia

  

float representation

     

IEEE 754标准将binary32指定为:

     
      
  • 符号位:1位
  •   
  • 指数宽度:8位
  •   
  • 显着精确度:24(明确存储23个)
  •   
     

这给出了6到9个有效十进制数字的精度(如果a   最多6个有效小数的十进制字符串转换为IEEE   754单精度然后转换回相同的数量   有效小数,则最终字符串应与原始字符串匹配;   如果IEEE 754单精度转换为十进制字符串   至少有9个有效小数,然后转换回单个,   然后最后的号码必须与原件相符。

在双倍的情况下,再次来自Wikipedia

  

double representation

     

双精度二进制浮点是一种常用的格式   PC由于其在单精度浮点范围上的范围更广,因此   尽管它的性能和带宽成本。与单精度一样   浮点格式,它在整数时缺乏精度   与相同大小的整数格式进行比较。众所周知   简单地说是双倍。 IEEE 754标准将binary64指定为   具有:

     
      
  • 符号位:1位
  •   
  • 指数宽度:11位
  •   
  • 显着精度:53位(显式存储52位)
  •   
     

这给出了15-17的重要意义   十进制数字精度。如果十进制字符串最多为15   然后将有效小数转换为IEEE 754双精度   转换回相同数量的有效小数,然后   final字符串应与原始字符串匹配;如果IEEE 754加倍   precision将转换为至少为17的十进制字符串   有效小数然后转换回双倍,然后是最终   号码必须与原件匹配。

另一方面,你不能指望如果你有一个浮点数并以更精确的方式打印出真正存储的数据,其余数字将填充为0。编译器无法想象你想要做的技巧。