双重和long double:我的电脑上是否相同?

时间:2017-03-23 05:26:59

标签: c gcc floating-point numerical-methods

这是ANSI C代码:

   float        x = 3.14159264351134890172;
   double       y = 3.14159264351134890172;
   long double  z = 3.14159264351134890172;

   printf("%f\n",x);
   printf("%f\n",y);
   printf("%f\n",z);
   printf("%.20f\n",x);
   printf("%.20f\n",y);
   printf("%.20f\n",z);

此代码的输出为:

3.141593
3.141593
3.141593
3.14159274101257324219
3.14159264351134881466
3.14159264351134881466

参见最后一行输出。我已经读过long double给出了小数点后19位的准确度。但是在这里我得到小数点后的15位精度。因此,我的计算机中doublelong double之间没有区别。我在CentOS上使用linux内核2.6.32-358.el6.x86_64。 我的C编译器是gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)

为什么会这样?如果它取决于计算机硬件/架构,我如何购买我的linux机器,其中long double比double更精确? 它还依赖于我的C编译器吗?如果是,我该如何选择我的C编译器?

float值范围为1.2E-38 to 3.4E+38。我不明白。从上面的例子中我们看到我们无法在float变量中正确存储小数十进制数,例如3.1415926。我的机器只能在float变量中正确存储3.141592。所以我丢失了最后7位数,这是6。那为什么我们说float范围是1.2 * 10 ^ -38?

不是我们不能存储最多10 ^ -38但我们可以在C中存储最多10 ^ -6的float变量吗?

2 个答案:

答案 0 :(得分:5)

首先,您应使用long double打印%Lf值。

其次,如果您希望long double变量包含无法表示为double的值,则不应使用double常量对其进行初始化。 3.14159264351134890172的类型为double,如果您的编译器将FLT_EVAL_METHOD定义为0或1,则使用long double z = 3.14159264351134890172;z设置为double值,即使类型long double可以在您的平台上更紧密地表示该常量。相反,该行应为:

long double  z = 3.14159264351134890172L;

在“浮动值范围是1.2E-38到3.4E + 38 ...”之后,您的问题的简短答案是您的机器上的浮点格式是基数2,并且可表示的值不相同在这些格式中,就像它们在基数10中表示一样。平台上的float类型提供了精确的24个二进制数字。类型double提供53,您应该能够期望long double提供64.对于StackOverflow格式,长答案太长,但您可以从阅读http://floating-point-gui.de开始。< / p>

答案 1 :(得分:1)

存在有助于回答OP调查的值,可以直接打印以辨别doublelong double的相似之处。他们可以完全一样。

要查找各种浮点类型的精度,请打印***_MANT_DIG

  

浮点有效数中的基数 - FLT_RADIX个数,p
    C11§5.2.4.2.211

#include <float.h>
printf("FLT_RADIX         %d\n", FLT_RADIX);  // Almost always 2
printf("DBL_MANT_DIG      %d\n", DBL_MANT_DIG);
printf("LDBL_MANT_DIG     %d\n", LDBL_MANT_DIG);

要查找要打印的与FP精确值匹配的十进制数字,请使用***_DIG(往返“text-FP-text”按预期方式)

printf("DBL_DIG           %d\n", DBL_DIG);
printf("LDBL_DIG          %d\n", LDBL_DIG);

要查找可以影响FP精确值的打印小数位数,请使用***_DECIMAL_DIG(预期的往返“FP-text-FP”)

printf("DBL_DECIMAL_DIG   %d\n", DBL_DECIMAL_DIG);
printf("LDBL_DECIMAL_DIG  %d\n", LDBL_DECIMAL_DIG);

double d = 3;
long double ld = 3;
printf("(double) 1/3      %.*e %.*e\n", DBL_DIG - 1, 1 / d,
    DBL_DECIMAL_DIG - 1, 1 / d);
printf("(long double) 1/3 %.*Le %.*Le\n", LDBL_DIG - 1, 1 / ld,
    LDBL_DECIMAL_DIG - 1, 1 / ld);

示例输出

FLT_RADIX         2
DBL_MANT_DIG      53
LDBL_MANT_DIG     64
DBL_DIG           15
LDBL_DIG          18
DBL_DECIMAL_DIG   17
LDBL_DECIMAL_DIG  21
(double) 1/3      3.33333333333333e-01 3.3333333333333331e-01
(long double) 1/3 3.33333333333333333e-01 3.33333333333333333342e-01

注意:
对于范围问题,请打印***_MAX, ***_MIN 请务必在L的打印说明符中使用long double