原码、反码、补码、移码和数值计算
欢迎访问我的个⼈站点,。
前⾔
  计算机的数值编码和运算应该是本科⼀年级就会学习的基础知识。从软件开发这个⾓度来说,很多时候这些知识没有在开发过程中得到有效的利⽤和实践。
  不巧,最近在做的⼀个项⽬,常常需要从补码的⾓度考虑数值表⽰和相关关系。因此,也就趁此机会简单的写⼀写。
数值表⽰
真值,机器数
  机器数就是数值在计算机中的⼆进制表⽰,数值有正负之分,因此机器数⽤最⾼位来表⽰数值的符号,0 代表正数,1 代表负数。根据表⽰⽅法不同,机器数分为:原码、反码、补码、移码等。
  真值就是带正负的真实⼗进制值。
原码
  原码很简单,就是最⾼位作为符号位,其余位表⽰真值的绝对值。
反码
  正数的反码就是其原码本⾝,负数的反码则是原码除符号位外,其余位取反。
  反码的运算⽅法为循环进位,即最⾼位的进位要加到最低位来。如:8位为例:11111110(-1) + 11111110(-1) = 11111100 + 1 = 11111101(-2)
  产⽣的原因:计算机的所有计算本质上都是加法,然⽽若正负值相加时让计算机判断符号位来选择运算⽅式会使得加法电路设计变得复杂,但是若直接让符号位参与运算则会带来1 + (-1) = -2 (8位为例:00000001 + 10000001 = 10000010)等等问题。反码的提出就是为了解决符号位参与运算的加法问题。
补码
  反码是⼀个不完美的解决⽅案,有不近⼈意的问题。⽐如: 8位为例,00000000 和 11111111都可以表⽰零,⼀个+0,⼀个-0。为了解决这个问题,引⼊补码来表⽰数值。
  正数的补码是其原码本⾝,负数的补码是其反码 + 1 。这个设计使得加法运算满⾜⼀个等式:a(补) + b(补) = (a + b)(补),由此,不管符号为何,直接参与运算都能得到正确的结果。⽬前补码是最佳的解决⽅案。现⾏的编程语⾔,都是⽤补码来表⽰数值和进⾏算数运算
  设计的原理:
  设计补码的原因是要解决表⽰反码表⽰ 0 的问题。
两个负数的补码相加
  计算机表⽰数值是有范围的,取决于⽤多少 bit 来表⽰,当加法计算超过了 bit 的长度,就会产⽣溢出,溢出的部分消失,这和模运算恰好⼀致。⽐如上限是 255,则5 mod 255 = 5,260 mod 255 = 5。我们可以说,在8位的情况下,5 和 260 是等价的。同理,在负数的情况下(反向理解),我们可以⽤负数的模除值等价负数,这样相当于⽤正数 (负数的模除值为正数) 表⽰了负数。
  根据模运算的运算法则,(a+b) mod m = [(a mod m) + (b mod m)] mod m ,在m为最⼤值的情况下,数 mod m的值就是数的反码。反码 + 1等价于m + 1并不破坏等式,同时保证了符号的正确和0的正确表⽰。
移码
  移码则是把补码的符号位取反,常常⽤在浮点数值的⼆进制表⽰中。
浮点的⼆进制表⽰
  浮点数的⼆进制表⽰⽐较特殊,整个⼆进制位分为三个部分:
类型符号位阶码尾数总位数
float182332
double1115264
  设阶码为 e,尾数为 m,则浮点的值为: m∗2e,其中阶码是⽤移码表⽰。
  ⽤移码表⽰的原因在于,阶码作为指数是有正负的,⽤移码表⽰能在不考虑符号的情况下⽐较浮点数⼤⼩。如:(8位情况下) 11111111 是最⼩值,00000000 是 0如果不考虑符号,则11111111 > 00000000显然不⽅便。⽽⽤移码则:11111111 -> 00000001,00000000 -> 10000000⼤⼩⼀下就
⽐较出来了。
  阶码确定浮点数的取值范围,尾数确定浮点数的精度。
数学运算
  上⾯也说到了,计算机的数值运算是通过补码完成的。两个数的补码进⾏加法运算得到最终的值。若要显⽰成⼈类可读,则通过补码的定义转换成真值。
整型溢出
  数值运算时极易发⽣整型溢出,直接通过补码的变化来判断溢出是否发⽣是⾮常准确的。
  我们把最⾼位 (符号位) 紧挨着的那⼀位称为最⾼有效位,那么,若符号位和最⾼有效位只有⼀个发⽣了进位,则出现了整型溢出。Processing math: 100%

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。