计算机中带符号的整数为何采用二进制的补码进行存储?

本贴最后更新于 2450 天前,其中的信息可能已经物是人非

我们都知道在计算机内部数据的存储和运算都采用二进制,是因为计算机是由很多晶体管组成的,而晶体管只有 2 种状态,恰好可以用二进制的 0 和 1 表示,并且采用二进制可以使得计算机内部的运算规则简单,稳定性高。在计算机中存在实数和整数,而整数又分为无符号整数和有符号整数,无符号的整数表示很简单,直接采用其二进制形式表示即可,而对于有符号数的表示却成了问题,如何表示正负?如何去处理正负号?下面来具体说下其中的原因,在这之前先了解一下原码、反码和补码这几个概念。

1.原码、反码和补码的概念

  在了解原码、反码和补码之前先说一下有符号数和无符号数。用过 C 语言的都知道在 C 语言中用 signed 和 unsigned 来标识一个数是否是有符号还是无符号类型的。对于一个 8bit 的二进制来说,若当做无符号数处理,其能表示的整型值范围是 0255,但是这样表示数据就有个局限性,如果数据是负的该如何表示?因此就引入了有符号类型的概念,对于有符号类型,规定取最高位为符号位,若最高位为 0,则为正数,否则为负数,这样一来对于 8 位二进制,示数值的就只有 7 位了,能够表示的非负数值范围变为 0127,负值范围为-127-1,相当于可以理解为将无符号类型能够表示的 128255 拿来去表示-127~-1 了。事实上,在计算机内部存储中,计算机自己是无法去区分无符号还是有符号类型的,对于 255 和-1,在计算机内部存储的都是 11111111。换个角度来说,如果事先知道内存中存储了这样一个 8 位二进制 11111111,但是谁也不能肯定它具体表示什么数值,是-1 还是 255?这个是需要靠程序员自己去指定的,如果指定为无符号类型,则编译器则通过相应指令将其转换为数值 255。事实上对于-x 的二进制补码表示形式和(256-x)(256-x 当做无符号类型处理)的二进制表示形式相同,从这里可以略微了解了补码的含义了。在教材中对于原码、反码以及补码一般是这么定义的:

  对于正数原码、反码以及补码是其本身。负数的原码是其本身,反码是对原码除符号位之外的各位取反,补码则是反码加 1。

  因为(-x)的二进制补码形式和 256-x 的二进制表示形式相同,而 255-x 相当于对 x 的每一位取反,那么 256-x 就是 255-x 后加 1。

  注意:1)原码、反码、补码的概念是针对有符号类型而言的。

     2)实数始终是有符号类型的(实数并不是采用补码形式存储的,具体可参考《浅谈 C/C++ 的浮点数在内存中的存储方式》一文),整型数据包括无符号和有符号类型的。

2.采用补码表示带符号的整数的原因

  对于有符号类型的整数,有原码、反码和补码三种形式,最后选择了补码来表示,具体来说有下面几点原因。

  1)能够统一 +0 和-0 的表示

  采用原码表示,+0 的二进制表示形式为 0 000 0000,而-0 的二进制表示形式为 1 000 0000;

  采用反码表示,+0 的二进制表示形式为 0 000 0000,而-0 的二进制表示形式为 1 111 1111;

  采用补码表示,+0 的二进制表示形式为 0 000 0000,而-0 的二进制表示形式为 1 111 1111+1=1 0000 0000,因为计算机会进行截断,只取低 8 位,所以-0 的补码表示形式为 0000 0000。

  从上面可以看出只有用补码表示,+0 和-0 的表示形式才一致。正因为如此,所以补码的表示范围比原码和反码表示的范围都要大,用补码能够表示的范围为-128127,0127 分别用 0000000001111111 来表示,而-127-1 则用 10000001~11111111 来表示,多出的 10000000 则用来表示-128。因此对于任何一个 n 位的二进制,假若表示带符号的整数,其表示范围为-2^(n-1)~2^(n-1)-1,且有 MAX+1=MIN。看下面一段代码:

char ch=127;
ch++;

  ch 的值是多少?它的值是-128,读者可以上机验证一下。

  假如不采用补码来表示,那么计算机中需要对 +0 和-0 区别对待,显然这个对于设计来说要增加难度,而且不符合运算规则。

  2)对于有符号整数的运算能够把符号位同数值位为一起处理

  由于将最高位作为符号位处理,不具有实际的数值意义,那么如何在进行运算时处理这个符号位?如果单独把符号位进行处理,显然又会增加电子器件的设计难度和 CPU 指令设计的难度,但是采用补码能够很好地解决这个问题。下面举例说明:

  比如-2+3=1

  如果采用原码表示(把符号位同数值位一起处理):

  1 000 0010+0 000 0011=1 000 0101=(-5)原,显然这个结果是错误的。

  如果采用反码表示

  1 111 1101+0 000 0011=1 0000 0000=0 0000000=(+0)反,显然这个结果也是错误的。

  如果采用补码表示

  1 111 1110+0 000 0011=1 0000 0001=0000 0001=(1)补,结果是正确的。

  从上面可以看出,当把符号位同数值位一起进行处理时,只有补码的运算才是正确的。如果不把符号位和数值位一起处理,会给 CPU 指令的设计带来很大的困难,如果把符号位单独考虑的话,CPU 指令还要特意对最高位进行判断,这个对于计算机的最底层实现来说是很困难的。

  3)能够简化运算规则

  对于-2+3=1 这个例子来说,可以看作是 3-2=1,也即[3]+[-2]=1,从上面的运算过程可知采用补码运算相当于是

  [3]补 +[-2]补=[1]补,也即可以把减法运算转换为加法运算。这样一来的好处是在设计电子器件时,只需要设计加法器即可,不需要单独再设计减法器。

  总的来说,采用补码主要有以上几点好处,从而使得计算机从硬件设计上更加简单以及简化 CPU 指令的设计。

测试代码

#include

int main(void)
{ char ch=-1; char *p=(char *)&ch;
unsigned char uch=*p;
printf("%d\n",uch); //输出结果为 255
return 0;
}

Why int32 has max value 2^31 -1

Int32.MaxValue = 2^31 - 1 = 01111111111111111111111111111111 1 = 00000000000000000000000000000001 0 = 00000000000000000000000000000000 -1 = 11111111111111111111111111111111 Int32.MinValue = -2^31 = 10000000000000000000000000000000

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    21 引用 • 245 回帖 • 227 关注
  • abitmean

    有点意思就行了

    36 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 290 关注
  • Access
    1 引用 • 3 回帖 • 2 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 759 关注
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    267 引用 • 666 回帖 • 1 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖 • 3 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    12 引用 • 54 回帖 • 8 关注
  • Excel
    31 引用 • 28 回帖 • 3 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 249 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖 • 7 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 32 关注
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 146 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 4 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 626 关注
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 818 回帖
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 119 关注
  • 创业

    你比 99% 的人都优秀么?

    82 引用 • 1395 回帖 • 2 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 164 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 160 关注
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 701 关注
  • 导航

    各种网址链接、内容导航。

    43 引用 • 177 回帖
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 1 关注
  • 反馈

    Communication channel for makers and users.

    126 引用 • 930 回帖 • 273 关注