这是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位精度。因此,我的计算机中double
和long 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
变量吗?
答案 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调查的值,可以直接打印以辨别double
和long 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
。