C语⾔中printf⽤%d输出float类型数据,或以%f输出int型数据
的结果浮点型变量float
1.测试程序及结果
程序
#include"stdio.h"
int main()
{
float a = 7.5, b = 1.23, c = 1.24, d = 1.25;
double a1 = 7.5, b1 = 1.23, c1 = 1.24, d1 = 1.25;
int e = 0, f = 1,g= 0x7fffffff;
unsigned int h = 0xffffffff;
unsigned long long i = 0x401E000000000000,j= 0x3FF3AE147AE147AE,k= 0x3FF3D70A3D70A3D7,l= 0x3FF4000000000000;
printf("7.5_ d:%d\n7.5_x:0x%x\n7.5_llx:0x%llx\n", a,a,a);
printf("7.5_ d:%d\n7.5_x:0x%x\n7.5_llx:0x%llx\n\n",a1,a1 ,a1);
printf("1.23_ d:%d\n1.23_x:0x%x\n1.23_llx:0x%llx\n", b,b,b);
printf("1.23_ d:%d\n1.23_x:0x%x\n1.23_llx:0x%llx\n\n", b1,b1,b1);
printf("1.24_ d:%d\n1.24_x:0x%x\n1.24_llx:0x%llx\n", c,c,c);
printf("1.24_ d:%d\n1.24_x:0x%x\n1.24_llx:0x%llx\n\n",c1,c1, c1);
printf("1.25_ d:%d\n1.25_x:0x%x\n1.25_llx:0x%llx\n",d,d, d);
printf("1.25_ d:%d\n,1.25_x:0x%x\n1.25_llx:0x%llx\n\n",d1,d1, d1);
printf("0_f:%f\n\n",e);
printf("1_f:%f\n\n", f);
printf("0x7fffffff_f:%f\n\n",g);
printf("0xffffffff_f:%f\n\n", h);
printf("0x401E000000000000_f:%f\n\n", i);
printf("0x3FF3AE147AE147AE_f:%f\n\n",j);
printf("0x3FF3D70A3D70A3D7_f:%f\n\n", k);
printf("0x3FF4000000000000_f:%f\n\n",l);
return 0;
}
结果:
图1
2.结果分析
IEEE754标准
(1) 单精度(32位)浮点数的结构:
图2
名称长度⽐特位置
符号位 Sign (S) : 1bit (b31)
指数部分Exponent (E) : 8bit (b30-b23)
尾数部分Mantissa (M) : 23bit (b22-b0)
其中的指数部分(E)采⽤的偏置码(biased)的形式来表⽰正负指数,若E<127则为负的指数,否则为⾮负的指数。
另外尾数部分M存储的是当把⼀个浮点数规范化表⽰后的(⼆进制的)形式的zozooz的部分的⽐特串,共23位.求值⽅法: (-1)^S*(1.M)*2^(E-127) (公式1)
注意:%f输出float类型,输出6位⼩数,有效位数⼀般为7位;
(2) 双精度(64位)浮点数的结构:
图3
名称长度⽐特位置
符号位 Sign (S) : 1bit (b63)
指数部分Exponent (E) : 11bit (b62-b52)
尾数部分Mantissa (M) : 52bit (b51-b0)
双精度的指数部分(E)采⽤的偏置码为1023
求值⽅法:(-1)^S*(1.M)*2^(E-1023) (公式2)
注意:双精度数也可⽤%f格式输出,它的有效位⼀般为16位,给出⼩数6位。(这⼀点在计算⾦额的时候尤为重要,超过有效位的数字是⽆意义的,⼀般会出错。)
具体分析过程
1. float a=7.5, doule a1=7.5 结果解释:
(7.5)10=(111.1)2=1.111*2^2;
以Float在内存中存储:
S=0;
E=(2+127)10=10000001;
M=111;
图4
以Double在内存中存储:
S=0;
E=(2+1023)10=( 10000000001)2
M=111;
图5
虽然7.5在内存中以float(32Bit)存储,但是在printf函数输出的时候要转换为double(64Bit)位的结构(原因:因为float和double类型的数据⽤printf函数输出的时候都是以%f,没有区别,所以编译器在输出的时候,⽆论是double还是float类型都已double存储形式输出),所以在程序运⾏结果中⽆论是以float类型还是double类型存储的7.5⽤%llx输出出来都是0x401E000000000000,但是⽤%d和%x输出的都是0,这是因为%d和%x只取内存的低32位,从图5可以看出低32全为0,所以取出来为0.
2.float b=1.23,double b1= 1.23 结果解释:
(1.23)10=( 1.0011101011100001010001111010111)2= 1.0011101011100001010001111010111*2^0
以float类型在内存中存储:
S=0;
E=(0+127)10=01111111
M=0011101 0111000010100100
图6
以double类型在内存中存储:
S=0;
E=(0+1023)10=(01111111111)2
M=0011 10101110 00010100 01111010 11100001 01000111 10101110
图7
可以发现图1中将1.23定义为float类型和double类型打印出来的结果不⼀样,为什么会有这⼀现象的发
⽣呢?有两个原因,第⼀:千万不要以为凡是计算机输出的数字都是精确的。必须知道有些浮点数是没法⽤⼆进制精确表⽰的,例如这⾥的1.23,在内存中是近似保存的;第⼆:回到前⾯解释过的⼀个问题,float类型在内存中是以(32BIt)存储,⾸先将1.23以float的形式存储在内存中,存进去的是⼀个近似的数字,如图8所⽰,近似为1.230000019073486328125,16进制表⽰为:0x3f9d70a4,当⽤printf函数打印的时候,
将1.230000019073486328125(⽽不是1.23)转换为double类型,然后输出,所以结果为图9所⽰;
图8
图9
图9和图1的输出结果统⼀起来,图1中以float类型存储的1.23,与以double类型存储的1.23结果不同,就是以上的解释;还有⼀点,程序中⽤%d打印1.23出来遗传很长的数字,
从图9可以看出,因为内存的低32为不为0,所以才会有很长⼀串数字,这是因为1.23没法精确表⽰,只能近似表⽰导致位数过多。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论