为何数值在float取值范围内时,float与double输出小数仍有差异?
浮点数精度差异问题解答
根本原因
浮点数的「取值范围」和「存储精度」是两个完全独立的属性,数值落在取值范围内仅能保证不会触发溢出错误,不代表可以被该类型精确存储。
基础前提
当前主流C语言实现都遵循IEEE 754浮点数标准:
float为单精度浮点数,仅分配23位存储空间存尾数,换算为十进制有效位数约为6~7位double为双精度浮点数,分配52位存储空间存尾数,换算为十进制有效位数约为15~16位
另外,绝大多数十进制小数都无法用有限长度的二进制小数精确表示,不管是float还是double,存储的都只是目标数值的近似值,只是二者的近似精度存在明显差异。
对应两个疑问的具体解释
1. double强制转float后小数部分不一致
你定义的double a = 34.837864本身就无法被二进制浮点数精确存储,double类型因为尾数更长,存储的近似值更贴近原始数值;强制转换为float时,由于float尾数长度不足,会对double的存储值做截断或舍入处理,自然会出现小数部分不一致的情况。
2. 同初始值的float和double输出差异
你的测试代码如下:
float a = 3.38776326737464747726337264343434334434343; double b = 3.38776326737464747726337264343434334434343; printf("%.16f\n%.16lf",a,b);
你给出的初始值十进制有效位数超过20位,远高于float的6~7位有效位上限:
- 赋值给
float a时,编译器会自动舍入到float能表示的最接近的近似值,仅前6~7位有效数字和原始值一致,后续都是误差位 - 赋值给
double b时,因为double有效位可达15~16位,前16位有效数字都能和原始值保持近似一致
所以用%.16f输出16位小数时,二者的差异会非常明显。
内容的提问来源于stack exchange,提问作者Tenko
相关产品推荐
相关产品推荐

