小数在内存中是如何存储的
| 分类: C 程序设计 |
上节讲到,C语言中的小数可以使用指数形式来表示,即
在内存中,小数也是以指数形式来表示的,但又和C语言中的有所区别。小数在被存储到内存前,首先转换为下面的形式:
其中,2 是固定的,不需要在内存中体现出来;正负号、指数(n)、尾数(a) 是变化的,需要占用内存空间来表示。这样,float、double 在内存中就被分成了三部分,如下图所示:
aEn或aen,它等价于a×10n。在内存中,小数也是以指数形式来表示的,但又和C语言中的有所区别。小数在被存储到内存前,首先转换为下面的形式:
a × 2
其中,2 是固定的,不需要在内存中体现出来;正负号、指数(n)、尾数(a) 是变化的,需要占用内存空间来表示。这样,float、double 在内存中就被分成了三部分,如下图所示:
例如对于 19.625,整数部分的二进制形式为:
所有的小数被转换成指数形式后,尾数的整数部分都为1,无需在内存中提现出来,所以干脆将其截去,只把小数点后面的二进制放入内存中的尾数部分(23Bits)。对于 1.0011101,尾数部分就是 0011101。
C语言把整数作为定点数,而把小数作为浮点数。定点数必须转换为补码再写入内存,浮点数没有这个过程,直接写入原码。小数被转换成指数形式后,指数有正有负,在内存中不但要能表现其值,还要能表现其正负。而指数是以原码形式存储的,没有符号位,所以要设计一个巧妙的办法来区分正负。
对于 float,指数占用8Bits,能表示从 0~255 的值,取其中间值 127,指数在写入内存前先加上127,读取时再减去127,正数负数就显而易见了。19.625 转换后的指数为 4,4+127 = 131 =1000 0011。
综上所述,float 类型的 19.625 在内存中的值为:0 - 10000011 - 001 1101 0000 0000 0000 0000。
下面我们使用代码来验证一下:
19 = 1×24
0.625 = 1×2-1
19.625 = 10011.101
由于尾数 a 必须 1 ≤ a < 2,所以还需要再将小数点向左移动4位:19.625 = 10011.101 = 1.0011101×24
此时尾数为 1.0011101,指数为 4。所有的小数被转换成指数形式后,尾数的整数部分都为1,无需在内存中提现出来,所以干脆将其截去,只把小数点后面的二进制放入内存中的尾数部分(23Bits)。对于 1.0011101,尾数部分就是 0011101。
C语言把整数作为定点数,而把小数作为浮点数。定点数必须转换为补码再写入内存,浮点数没有这个过程,直接写入原码。小数被转换成指数形式后,指数有正有负,在内存中不但要能表现其值,还要能表现其正负。而指数是以原码形式存储的,没有符号位,所以要设计一个巧妙的办法来区分正负。
对于 float,指数占用8Bits,能表示从 0~255 的值,取其中间值 127,指数在写入内存前先加上127,读取时再减去127,正数负数就显而易见了。19.625 转换后的指数为 4,4+127 = 131 =
综上所述,float 类型的 19.625 在内存中的值为:0 - 10000011 - 001 1101 0000 0000 0000 0000。
下面我们使用代码来验证一下:
运行结果:
0, 0X4, 0X1D0000
float 和 double 的精度是由尾数的位数决定。内存中的尾数只保存了小数点后面的部分,其整数部分始终是一个隐含着的“1“,它是不变的,不会对精度造成影响。
float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即 float 的精度为 6~7 位有效数字。
double:2^52 = 4503599627370496,一共16位,同理,double 的精度为 15~16 位。
当小数的尾数部分过长时,多出的位数就会被直接截去,这时保存的就不是小数的真实值,而是一个近似值。在上节的示例中,我们看到 128.101 的输出结果就是一个近似值。
128.101 转换成二进制为10000000.0001100111011011001000101101,向左移动7位后为 1.00000000001100111011011001000101101,由此可见,尾数部分为 000
0000 0001 1001 1101 1011
001000101101,将多出的二进制截去后为 000 0000 0001 1001 1101
1011。下面的代码有力地证明了这一点:
0, 0X4, 0X1D0000
C语言不能直接输出二进制形式,一般输出十六进制即可,十六进制能够很方便地转换成二进制。
精度
精度指测量值与真实值的接近程度,在C语言中表现为输出值和真实值的接近程度。float 和 double 的精度是由尾数的位数决定。内存中的尾数只保存了小数点后面的部分,其整数部分始终是一个隐含着的“1“,它是不变的,不会对精度造成影响。
float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即 float 的精度为 6~7 位有效数字。
double:2^52 = 4503599627370496,一共16位,同理,double 的精度为 15~16 位。
取值范围和近似值
float 和 double 在内存中的指数和尾数的位数都是有限的,小数过大或过小都会发生溢出。float 的取值范围为 -2^128 ~ +2^128,也即 -3.40E+38 ~ +3.40E+38;double 的取值范围为 -2^1024 ~ +2^1024,也即 -1.79E+308 ~ +1.79E+308。当小数的尾数部分过长时,多出的位数就会被直接截去,这时保存的就不是小数的真实值,而是一个近似值。在上节的示例中,我们看到 128.101 的输出结果就是一个近似值。
128.101 转换成二进制为
运行结果:
128.100998
0, 0X7, 0X19DB
最后对 float 和 double 做一下总结:
128.100998
0, 0X7, 0X19DB
最后对 float 和 double 做一下总结:
前一篇:整数在内存中是如何存储的
后一篇:C语言循环结构的嵌套

加载中…