十进制和浮动的精确值为double?

时间:2016-07-28 16:06:17

标签: c floating-point double precision

DBL_MAX

179769313486231570814527423731704356798070567525844996598917476803157260
780028538760589558632766878171540458953514382464234321326889464182768467
546703537516986049910576551282076245490090389328944075868508455133942304
583236903222948165808559332123348274797826204144723168738177180919299881
250404026184124858368.000000

但如果我这样做:

double a=1234567890123456789.0;
printf("%f",a);
  

1234567890123456768.000000

这里的精度是17位数。

double a=0.1234567890123456789;
printf("%.20f",a);
  

0.1234567890123456773

此处浮点后的精度为17位:

double a=1234567890.1234567890123456789;
printf("%.20f",a);

这会产生:

  

1234567890.12345671653747558594

现在,精度将是十进制的10位数+浮点数后的7位数,即17。

这是否意味着我只有17位数才能获得精确的double值?如果是,为什么DBL_MAX的位数超过300位?

2 个答案:

答案 0 :(得分:2)

与下一个double相比,典型double的重要性为15-16个十进制数字。

所有有限double都有与OP' s DBL_MAX = 1797693134862315708...一样的精确值。浮点数以对数方式分布。因此通常在0.5和1.0之间存在尽可能多的不同double,因为它们在2和4之间。

此分发意味着OP的第二大号码仅匹配DBL_MAX至300多位数中的前16位。见下文。

  

这是否意味着我只有17位数才能获得精确的双倍值?如果是,那么DBL_MAX的所有位数的使用是多少300多个?

double,因为binary64可以代表完全约2 ** 64个不同的数字。 0.1234567890123456789不是其中之一。最接近的double0.1234567890123456773...请注意,它与至少15个(DBL_DIG)位匹配。

通常这意味着double完全值与其与下一个double的相对差异并不重要。

1e3001e-300的值是范围之一,而不是精确度。

int main(void) {
  printf("%.*e\n", DBL_DECIMAL_DIG + 2, DBL_MAX);
  printf("%.*e\n", DBL_DECIMAL_DIG + 2, nextafter(DBL_MAX,0));
  printf("%.*e\n", DBL_DECIMAL_DIG + 2, nextafter(0, 1));
}

输出

1.7976931348623157081e+308
1.7976931348623155086e+308
4.9406564584124654418e-324

考虑使用printf("%.*e", DBL_DECIMAL_DIG-1, a);而非printf("%.20f",a);来更清晰地了解double的{​​{3}}。如果您已准备好使用十六进制表示法,请尝试printf("%a",a);

答案 1 :(得分:1)

用于表示C双精度的最常用系统是IEEE 754 64位二进制浮点。它是一个基础2系统。这意味着可精确表示的数字具有相对较短的二进制表示 - 适合64位 - 但不一定是短十进制表示。

的最大有限数的精确值是2^1024 - 2^971或179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368

由于数字的粒度,这不是非常有用的信息。连续数字相差大约10 ^ 16.9的一部分。例如,旁边表示的最大数目是179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520

您不需要所有这些数字来区分它们。如果你知道你有这些数字之一,看到17个字符的前缀17976931348623157和17976931348623155就足以说明哪个。

将double转换为十进制字符串的库函数存在问题。你应该打印多少位数?以下是一些选项:

  • 打印确切的值。几乎总是做错事,因为你会打印很多不能传达任何有用信息的数字。
  • 打印足够的数字以区分您开始使用的双倍数字。例如,这是Java的Double.toString的选择。这样可以从打印值中精确恢复双倍。
  • 仅打印固定位数。制作整洁的报告。