2015年11月7日15:54:30补充:关于浮点数的取值范围
之前一直对浮点数的二进制表示和取值范围不太理解,最近看了很多资料,终于有一个比较清晰的认识,记录一下。
首先,很多浮点数不能用二进制准确的表示,比如0.4。
第二,浮点数能表示的精度有限,这个好理解,跟一个整数太大了无法表示一样,小数太长,肯定也无法表示。
详细说一下为什么很短的小数也无法用二进制准确表示。
其实和整数的表示方法一样,小数也是依次以底数乘以二的幂相加来表示小数。如整数二进制表示从右到左依次为2^0+2^1+2^2+.....2^n,小数从左到右则是2^-1+2^-2+2^-3+........2^-n(底数0或1省略掉了)。比如十进制0.75对应的二进制是0.11,即1*2^-1+1*2^-2即0.5+0.25=0.75。
但0.4用二进制就无法准确表示。前面0.75即3/4还可以表示为1/2^1+1/2^2即1/2+1/4,但0.4,2/5,无法用2的幂次方分之一相加来准确表示。
计算机实际存储二进制数的方式还有一点差别。实际存储中,将浮点数分为符号位 指数位 尾数位
32位的float类型中 最高位为符号位 0表示正 1表示负
紧挨着的8位是指数位 指数位也有符号位 是这八位中的最高位 0为正 1为负 且需要加上偏移量127
剩余的23位是尾数位
例如0.4用乘2取整进1法计算二进制
0.4x2=0.8x2=1.6x2=1.2x2=0.4x2=0.8x2=1.6x2=1.2x2=0.4x2=0.8x2=1.6x2=1.2x2=0.4x2=0.8x2.........循环
0 1 1 0 0 1 1 0 0 1 1 0 0...........循环
算出0.4的二进制表示为0.0110011001100110011001100
使用科学计数法表示为1.10011001100110011001100 x 2^-2
符号位 正 0
指数位 -2 + 127 = 125 = 11111101
尾数位 10011001100110011001100
完整表示则为0 11111101 10011001100110011001100
---------------------------------------分割线--------------------------------------------
最近在自学C的数据类型时,看到各种类型的取值范围。关于各种范围是怎么算出来的,之前在了解各种字符集的时候了解过一些,正好现在一起整理一下。
在这之前,最重要的一点,计算机存储任何信息,最终都是以0和1来存储的,即二进制存储。
在这个前提下,计算机如何保存各种信息?计算机最先是在美国,美国使用的是英语,那么英文的各种信息计算机改如何表示呢?
答案是编码,即将文字信息转换为计算机可以识别的二进制,对每一个字符,都以一个二进制的数字相对应。
以ASCII编码为例,字母A对应的是01000001;字母F对应的是01000110;数字8对应的是00111000。英文字母只有26个,算上大小写,加上0到9的数字,只有62个,再加上各种符号,凑到128个,用一个字节就可以存储。
为什么呢?因为一个字节可以包含八位二进制数,八位二进制数最大为11111111,换成10进制即255,所以八位二进制数最大范围可以表示0~255个字符。128个字符只需要用到七位即0~127,这样还多下一位没有用上。
但ASCII并不适用于中文,常用汉字就多达几千个,ASCII远远不能表示。这样GBK应运而生。解决办法也很简单,一个字节表示不了,就再加一个字节。两个字节能够表达0~65535,足够处理常用汉字。另外有UTF编码,可用于全球所有语言。
再说说数据类型的取值范围:
放到数据类型上也是一样的,一个无符号数据类型假如占据一个字节,那么表示范围就是0~255(2的8次方减1),两个字节就是0~65535(2的16次方减1)。如果是有符号类型,则需要一位(最高位)表示符号位,一字节范围为-128~127,两字节为-32768~32767。以此类推。
so最核心的是一个十进制和二进制互转的问题。
PS:关于一字节有符号类型范围下限为什么是-128而不是-127,因为+0和-0是一样的,不需要重复表示,这样就多出来一个位子,用来表示-128了。那为什么是-128不是128呢,因为最高位是符号位,0表示正数,1表示负数,所以正数最大只能有127。