user-0 提问: C 语言float奇怪问题

回复:
user: user-1
content: 引用 18 楼 mymtom 的回复:[quote=引用 2 楼 armfpga123 的回复:] 尾数是23位，为什么就精确到小数点后面6位呢？  这个根本不是什么精确到小数点后6位的问题，只是printf对%f的格式打印为小数点后6位。  实际的原因是float的有效位数只有7.22位 log(2^(23 + 1)) = 7.22 float f = 1.9865455f;  这个数超过了float的精度范围所以1.986545这7位是可以存储到float类型的，但是double类型就可以达到这个精度   #include <stdio.h>  int main(int argc, char *argv[]) {         float  f = 1.9865455f;         double d = 1.9865455;          printf("%20.10f\n",f);         printf("%20.10f\n",d);          return 0; }   输出为：         1.9865454435         1.9865455000[/quote] 7.22 是说 最大可表示的精度 另外 二进制精度和十进制精度不是一会事。 能够表示到本位无误差的（误差小于本位的1/10），才是可以精确表示的精度， 然后多取一位，就是有效数据的位数。 之所以不用7位有效数字， 因为6~7位有效数字之间的所有浮点数，不是全部都可以精确表示的。 这样应该是7位有效数字。 但是，计算的中间结果，需要多保留一位有效数字。 所以按照6位有效数字，才能保证计算精度。

user: user-2
content: 引用 2 楼 armfpga123 的回复:尾数是23位，为什么就精确到小数点后面6位呢？  这个根本不是什么精确到小数点后6位的问题，只是printf对%f的格式打印为小数点后6位。  实际的原因是float的有效位数只有7.22位 log(2^(23 + 1)) = 7.22 float f = 1.9865455f;  这个数超过了float的精度范围所以1.986545这7位是可以存储到float类型的，但是double类型就可以达到这个精度   #include <stdio.h>  int main(int argc, char *argv[]) {         float  f = 1.9865455f;         double d = 1.9865455;          printf("%20.10f\n",f);         printf("%20.10f\n",d);          return 0; }   输出为：         1.9865454435         1.9865455000

user: user-3
content: 看看这里吧，讲得很清楚了，希望对你有帮助  基本上和楼上讲的差不多，但说错了一点，2^23=8388608是7位，为了100%保证精度，所以取6位。

user: user-4
content: 引用 楼主 heyuntao112356 的回复:#include <stdio.h>  int main(int argc,char *argv[]) {     float f = 1.9865455f;      printf("%f",f);      return 0;     }  输出结果：1.986545  解释如下：  按照IEEE 754对float类型的规定，f 在内存中的二进制存放如下：  0011 1111 1111 1110 0100 0111 0001 1111  其值为：1.111 1110 0100 0111 0001 1111 * 2^(127-127)  对应的十进制数值为：  1 + 1*2^-1 + 1*2^-2 + 1*2^-3 + 1*2^-4 + 1*2^-5 + 1*2^-6 + 0*2^-7 + ... +  0*2^-18 + 1*2^-19 + 1*2^-20 + 1*2^-21 + 1*2^-22 + 1*2^-23   =1.98654544353485107421875  问题：为什么输出结果是1.986545而不是1.98654544353485107421875？  为什么printf只输出小数点后面6位？  为什么float类型只精确到小数点后面6位？  求详细解释。   2^-23=0.00000011920928955078125,于是楼主就以为可以精确到23位十进小数了？ 只要想想你能用浮点数表示 0.00000011920928955078126吗？

user: user-5
content: 你看一下C语言里面FLOAT类型的定义吧.

user: user-1
content: 抱歉 10^6 ~ 10^7 应该是6~7 位有效数字

user: user-6
content: 楼上正解 引用 3 楼 youth0826 的回复:printf("%f",f)是默认的6位小数点，控制格式输出可以自己改的 比如这样： printf("%.24f",f);

user: user-1
content: 2^24  ~= 10^8  所以精度不可能超过8 所以精度为 10^6 ~ 10^7 所以共有6位有效数字，是可以保证正确的。

user: user-7
content: 引用 11 楼 angel_su 的回复:[quote=引用 10 楼 armfpga123 的回复:] 为什么二进制的23位就只能精确到十进制的小数点后面6位呢？ 我被这个问题困扰好久了，求详细解释。 你不要老想着2进制转10十进制，这个肯定可以完整得出。要倒过来想，大部分情况是要把10进制的源数据转成2进制，那如果如果有个数需要2^-24或者更小的项次，那么它还不是裁断成23位，因此只能说到精确到小数点6位...[/quote]  为什么截断成23位就是精确到小数点后面6位呢？可以详细解释下吗？

user: user-8
content: printf("%f",f)是默认的6位小数点，控制格式输出可以自己改的 比如这样： printf("%.24f",f);

user: user-7
content: 尾数是23位，为什么就精确到小数点后面6位呢？

user: user-9
content: 引用 10 楼 armfpga123 的回复:为什么二进制的23位就只能精确到十进制的小数点后面6位呢？ 我被这个问题困扰好久了，求详细解释。 你不要老想着2进制转10十进制，这个肯定可以完整得出。要倒过来想，大部分情况是要把10进制的源数据转成2进制，那如果如果有个数需要2^-24或者更小的项次，那么它还不是裁断成23位，因此只能说到精确到小数点6位...

user: user-7
content: 为什么二进制的23位就只能精确到十进制的小数点后面6位呢？ 我被这个问题困扰好久了，求详细解释。

user: user-10
content: 引用 7 楼 armfpga123 的回复:为什么尾数是23位就只能精确到小数点后面6位？  哥，你那23位是二进制23位

user: user-11
content: 引用 楼主 heyuntao112356 的回复:#include <stdio.h>  int main(int argc,char *argv[]) {     float f = 1.9865455f;      printf("%f",f);      return 0;     }  输出结果：1.986545  解释如下：  按照IEEE 754对float类型的规定，f 在内存中的二进制存放如下：  0011 1111 1111 1110 0100 0111 0001 1111  其值为：1.111 1110 0100 0111 0001 1111 * 2^(127-127)  对应的十进制数值为：  1 + 1*2^-1 + 1*2^-2 + 1*2^-3 + 1*2^-4 + 1*2^-5 + 1*2^-6 + 0*2^-7 + ... +  0*2^-18 + 1*2^-19 + 1*2^-20 + 1*2^-21 + 1*2^-22 + 1*2^-23   =1.98654544353485107421875  问题：为什么输出结果是1.986545而不是1.98654544353485107421875？  为什么printf只输出小数点后面6位？  为什么float类型只精确到小数点后面6位？  求详细解释。  %f 默认输出小数点后面6位, google prinf()函数，学习输出格式控制

user: user-12
content: 输出时printf函数输出格式决定的 精确到后六位是float类型的尾数位的个数决定的 算算尾数位是多少位，就知道为什么精确到后六位了

user: user-7
content: 为什么尾数是23位就只能精确到小数点后面6位？

user: user-13
content: 用10进制小数不能精确表示某些三进制小数0.1(3)=0.33333333333……(10) 同理，用二进制小数也不能精确表示某些10进制小数。  include\float.h ... #define DBL_DIG         15                      /* # of decimal digits of precision */ #define DBL_EPSILON     2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */ #define DBL_MANT_DIG    53                      /* # of bits in mantissa */ #define DBL_MAX         1.7976931348623158e+308 /* max value */ #define DBL_MAX_10_EXP  308                     /* max decimal exponent */ #define DBL_MAX_EXP     1024                    /* max binary exponent */ #define DBL_MIN         2.2250738585072014e-308 /* min positive value */ #define DBL_MIN_10_EXP  (-307)                  /* min decimal exponent */ #define DBL_MIN_EXP     (-1021)                 /* min binary exponent */ #define _DBL_RADIX      2                       /* exponent radix */ #define _DBL_ROUNDS     1                       /* addition rounding: near */  #define FLT_DIG         6                       /* # of decimal digits of precision */ #define FLT_EPSILON     1.192092896e-07F        /* smallest such that 1.0+FLT_EPSILON != 1.0 */ #define FLT_GUARD       0 #define FLT_MANT_DIG    24                      /* # of bits in mantissa */ #define FLT_MAX         3.402823466e+38F        /* max value */ #define FLT_MAX_10_EXP  38                      /* max decimal exponent */ #define FLT_MAX_EXP     128                     /* max binary exponent */ #define FLT_MIN         1.175494351e-38F        /* min positive value */ #define FLT_MIN_10_EXP  (-37)                   /* min decimal exponent */ #define FLT_MIN_EXP     (-125)                  /* min binary exponent */ #define FLT_NORMALIZE   0 #define FLT_RADIX       2                       /* exponent radix */ #define FLT_ROUNDS      1                       /* addition rounding: near */ ...

user: user-14
content: 引用 4 楼 gcgily 的回复:楼上正解 [quote=引用 3 楼 youth0826 的回复:] printf("%f",f)是默认的6位小数点，控制格式输出可以自己改的 比如这样： printf("%.24f",f);[/quote] 同意