C/C++中的整数和浮点数在计算机中是如何表示的?

一、整数在计算机中的表示

在C/C++中,整数一般分为无符号数(unsigned char、unsigned short、unsigned int等)和有符号数(char、short、int、long等),在计算机中通过补码来表示,那么有童鞋会问了,不是有那什么原码反码之类的吗?为什么不用它们而偏偏用补码呢?

一开始我也有这样的困惑,于是通过各种查,各种看,算是理解了一点点,这里不打算详细解释原码和反码,只举几个例子说明在计算机中为什么不用它们表示十进制数,而用补码来表示。

我们能认识0、1、2、3、、、9等自然数,然而计算机却不认识,计算机“笨”的只认识0和1,所以那些大神们就通过各种手段,将现实世界中的各种信息都转化为一连串由0和1组成的序列。然后计算机就通过不同的解读方式,对这一系列的01串串根据具体的上下文解释成不同的信息。

我们都知道1 + (-1) = 0,那么如果用原码、反码来表示这个会怎样呢?

原码:

     原码         十进制
  0000 0001         1
+ 1000 0001        -1
----------------
  1000 0010        -2

反码:

     反码         十进制
  0000 0001         1
+ 1111 1110        -1
----------------
  1111 1111        -0  // 需要通过转换为原码,才能直观的看出所表示的实际数字,原码:1000 0000

通过上面两个例子,我们看到,不管是用原码还是反码,都不能正确的表达结果。另外,我们可以发现,在原码和反码中,对于0的表示有两种,一种是0000 0000(+0),一种是1000 0000(-0),这也是一种缺陷,最好的方式是在给定一个十进制整数的范围内,该范围内的每一个数在相应的二进制表示中有且只有一个与之对应,也就是存在一一映射的关系。那么如何解决上述的问题呢?

终于等到补码登场了,一般主角都压轴,哈哈。补码,就是在反码的基础上再加1,比如-1的补码就是1111 1110 + 1 = 1111 1111,用补码来进行上面的计算就是:

     反码         十进制
  0000 0001         1
+ 1111 1111        -1
----------------
 1 0000 0000        0    // 最高位的1被丢弃

结果为0,符合我们的实际逻辑。我们再来看看前面提到的一一映射的问题,在C/C++中,char表示一个8bit的有符号整数,在计算机中用补码表示,所能表示的十进制范围为[-128, 127]共256个数,那么这个范围是怎么得来的呢?

   补码    十进制
0000 0000    0
0000 0001    1
...
...
...
0111 1111    127(2^7 - 1)
1000 0000    -128(-2^7 + 0)
1000 0001    -127(-2^7 + 1)
...
...
...
1111 1111    -1(-2^7 + 127)

从上面可以看出,前128个数表示正数(最高位以0开始),后128个表示负数(最高位以1开始)。对于unsigned char来说,由于其为无符号数,所以所能表示的最大范围为[0, 255]。对于其它的整数数据类型可以通过类似的方法得到他们的表示范围,感兴趣的童鞋可以自己算算试试。

二、小数在计算机中的表示

对于float来说,在一般机器上都是以四个字节即32bit来表示,那么它在计算机中是怎么表示的呢?

IEEE 754规定,对于32位的浮点数,最高位的那位表示符号位s,紧接着的8位是指数E,剩下的23位为有效数字M或者称为尾数。

图1 32位浮点数在计算机中的表示
图2 个人理解

在十进制中,对于任何一个小数都可以用科学计数法来表示,比如123.567的科学计数法就是1.23456*10^20.0097就是9.7*10^-3;同样地,在二进制的世界中,任何一个小数也可以用类似的科学技术法来表示,只不过不在以10为底,而是以2为底。那么对于十进制的123.5670.0097在二进制中如何表示呢?

十进制小数:123.567

在二进制中的表示:
1. 首先取整数部分123,用二进制中表示为1111011。
2. 小数部分.567如何表示?
我们都知道,在十进制整数进行二进制转化的时候有一个方法,就是对十进制数进行不断的除以2,然后取余数(要么为0,要么为1),然后按逆序排列就得到了十进制整数的二进制表示。
那么对于十进制的小数该如何用二进制表示是否找到了灵感?对,就是对小数部分不断的乘以2,然后对得到的新小数取整数部分(要么为0,要么为1)直到小数部分为0或者已经达到精度上限(比如所取得0、1已经达到23位了,再继续乘下去,对于32位的float来说,已经不能继续存储了)。

0.567 * 2 = 1.134 …… 取1 , 基数 = 0.134
0.134 * 2 = 0.268 …… 取0 , 基数 = 0.268
0.268 * 2 = 0.563 …… 取0 , 基数 = 0.563
0.563 * 2 = 1.126 …… 取1 , 基数 = 0.126
……
……
……
最终结果为:10010001001001101110100。(23位)
所以.567在二进制中的表示为:.10010001001001101110100。
因而123.567在二进制中的表示为:1111011.10010001001001101110100。
用科学计数法表示为:1.1110 1110 0100 0100 1001 1011 1010 0 * 2^6。
通过IEEE 754的规定,我们可以很容易将其在计算机中表示:
符号位:0
指数位:Exp - 127 = 6 --> Exp = 133 -->1000 0101
尾数部分:1110 1110 0100 0100 1001 101
【IEEE 754规定,在计算机内部保存M时(1.XXXXXXX),默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。】
所以123.567在计算机中的完整表示就是:
0 1000 0101 1110 1110 0100 0100 1001 101

通过在线工具,可以验证上面结果的正确性,如下图:

图3 123.567在计算机中的表示

对于0.0097也可以用同样的方法得到其在计算机内部的表示,这里就不在赘述了,有兴趣的童鞋可以自己尝试一下,然后通过上面提到的在线工具验证一下。

这里稍微再提一下,在C/C++中,float所能保持的精度一般为小数位6-7位,那么这个6或7是怎么得来的呢?通过上面我们知道,对于32位的浮点数,后23位表示的是小数部分,总共可以表示2^23 = 8388608,也就是说,后面的23位最多可以表示十进制小数的前7位小数位,通过四舍五入,至少可以保证6位的精度是正确的,至于第7位......呵呵!

好了,通过上面的描述,基本了解了float在计算机内存是如何表示的了,那么double在计算机中如何表示呢?其实和float的表示原理是一样的,只是double一般用64位bit来表示,最高位还是符号位,但是指数部分用了11位来表示,而剩余的52位全用来表示尾数(所能表示的精度一般为2^52 = ?15-16位),其余的规则和32位的float没啥区别,所以这里就仅放一张图,各位童鞋可以慢慢去体会。

图4 64位浮点数在计算机中的表示

后记

这是我在简书上发表的第一篇文章,希望自己能一直坚持下去,养成一个习惯。
对于文章中的不足之处,恳请各位读者批评指正。
简书给我的感觉就是三个字 -- 简洁、美。
感谢这个平台。

参考

(完)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容