c语⾔中float、double、longdouble在内存中存储⽅式
存储格式中的⼆机制转为浮点数:
浮点型变量在计算机内存中占⽤4个字节(4 Byte),即32-bit,⼀个浮点数由2部分组成:底数m 和指数e;
底数部分:使⽤2进制数来表⽰此浮点数的实际值;
指数部分:占⽤8=bit空间来表⽰,表⽰数值范围:0-255;后⾯介绍⽤于存储科学计数法中的指数部分,并且采⽤移位存储⽅式;
具体分析:
浮点数据就是按下表的格式存储在4个字节中:
Address+0 Address+1 Address+2 Address+3 Contents
SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
S部分: 表⽰浮点数正负,1为负数,0为正数。⼀位即可
E部分:指数加上127后的值的⼆进制数(why是加上了127之后的值?由于指数应可正可负,所以IEEE规定,此处算出的次⽅须减去127才是真正的指数。所以float的指数可从 -126到128.)
M部分:24-bit的底数(底数部分实际是占⽤24-bit的⼀个值,由于其最⾼位始终为 1 ,所以最⾼位省去不存储,在存储中只有23-bit。)
特例:浮点数为0时,指数和底数都为0,但此前的公式不成⽴。因为2的0次⽅为1,所以,0是个特例。这个特例也不⽤认为去⼲扰,编译器会⾃动去识别。
举例:看下-12.5在计算机中存储的具体数据:0xC1 0x48 0x00 0x00
⼆进制:11000001 01001000 00000000 00000000
格式:SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
可见:
S: 为1,是个负数。
E:(8-bit)为 10000010 转为10进制为130,130-127=3,即实际指数部分为3.
浮点型变量float
M:(23-bit)为 10010000000000000000000。底数实际上是:1.10010000000000000000000
现在,我们通过指数部分E的值来调整底数部分M的值。
调整⽅法为:如果指数E为负数,底数的⼩数点向左移,如果指数E为正数,底数的⼩数点向右移。⼩数点移动的位数由指数E的绝对值决定。
这⾥,E为正3,使⽤向右移3为即得: 1100.10000000000000000000
转换过程:⼩数点左边的1100 表⽰为 (1 × 2^3) + (1 × 2^2) + (0 × 2^1) + (0 × 2^0), 其结果为 12 。
⼩数点右边的 .100… 表⽰为 (1 × 2^-1) + (0 × 2^-2) + (0 × 2^-3) + ... ,其结果为.5 。
以上⼆值的和为12.5,由于S 为1,使⽤为负数,即-12.5 。所以,16进制 0XC1480000 是浮点数 -12.5 。
浮点数转存储格式的⼆进制数:
下⾯看下如何将⼀浮点数装换成计算机存储格式中的⼆进制数。举例将17.625换算成 float型。
1、转为⼆进制:10001.101
2、⼩数点,左移4位,变成1.0001101
3、这样底数为:1.0001101,指数为:4+127=131,⼆进制位:1000011
4、符号位为0,因为是正数;
5、合并:0 1000011 0001101后⾯补0,补成32-bit;
6、转成16进制:转换成16进制:0x41 8D 00 00
浮点数转成⼆进制代码形式代码:
1 #include<iostream>
2using namespace std;
3
4#define uchar unsigned char
5
6void binary_print(uchar c)
7 {
8for(int i = 0; i < 8; ++i)
9 {
10if((c << i) & 0x80)
11 cout << '1';
12else cout << '0';
13 }
14 cout << '';
15 }
16
17int main()
18 {
19float a;
20 uchar c_save[4];
21 uchar i;
22void *f;
23 f = &a;
24
25 cout<<"pls input a float num:";
26for(i=4;i!=0;i--)
27 binary_print(c_save[i-1]);
28 cout<<endl;
29
30return0;
31 }
C标准规定,float类型必须⾄少能表⽰6位有效数字,就像33.333 333这样的数字的⼩数点后的前6位;那么whyfloat能表⽰6位有效数字呢?
解释如下:⼗进制中的9,在⼆进制中的表⽰形式是1001,这也就是说: 表⽰⼗进制中的⼀位数在⼆进制中需要4bit,所以我们现在float 中具有24bit的精度,所以float在⼗进制中具有24/4=6,所以在⼗进制⾥,float能够精确到⼩数点后6位;
double呢?其实和float原理是⼀样的,只是double的位数更长⼀些⽽已;
注意点,double类型数据操作⽐float型运算要慢很多;
浮点值的上溢和下溢
假设系统中最⼤的float值为34E38,并进⾏如下操作:
float toobig = 3.4E38 * 100.0f ;
printf("%e\n", toobig);
会发⽣什么呢?这是⼀个上溢(overflow)的例⼦。当计算结果是⼀个⼤得不能表达的数时,会发⽣上溢。
相对应的,当表⽰⼀个float能表⽰的最⼩数时,对这个数进⾏除2操作,将会发⽣下溢。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论