上一篇:计算机中的数之一 无符号数与有符号数
原码
原码是机器数中最简单的一种表示形式,符号位为0表示正数,符号位为1表示负数,数值位即是真值的绝对值,故原码又称为带符号的绝对值表示。譬如101的原码是0,101。我们用逗号
"
,
"
","
","作为符号位和数值部分的分隔符。
原码正数定义
[
x
]
原
=
{
0
,
x
2
n
>
x
≥
0
2
n
−
x
,
0
≥
x
>
−
2
n
[x]_原=\begin{cases} 0,x \quad 2^n>x\geq 0\\ 2^n-x,0\geq x>-2^n\\ \end{cases}
[x]原={0,x2n>x≥02n−x,0≥x>−2n
解释
正数比较好理解。负数需要稍微解释下。为什么是
2
n
−
x
2^n-x
2n−x呢?
我们举个例子,具体体会下。比如-101这个二进制数将其表示为原码表示法。根据原码的含义我们直观可以写出1,101这个原码来。但是要用数学式子定义该怎么办呢?很容易想到把101加个负号(负负得正)然后再加上一个1000就可以了。
1
,
101
=
1000
−
(
−
101
)
=
1
,
101
1,101=1000-(-101)=1,101
1,101=1000−(−101)=1,101把这个具体的例子推向一般化就可以得到上述的公式了。
注意要点
这个定义有个问题?就是0的原码表示有两个。如果把0作为正数(0固然不是正数,只是把0放到上面那个表达式里计算原码),那么0的原码就是
0
,
0
0,0
0,0,如果把0作为负数,那么0的原码就是
2
−
0
=
10
−
0
=
1
,
0
2-0=10-0=1,0
2−0=10−0=1,0。可见
[
0
+
]
原
≠
[
0
−
]
原
[0_+]_原\neq[0_-]_原
[0+]原=[0−]原
原码小数定义
[
x
]
原
=
{
x
,
1
>
x
≥
0
1
−
x
,
0
≥
x
>
−
1
[x]_原=\begin{cases} x,\quad 1>x\geq 0\\ 1-x, \quad 0 \geq x>-1\\ \end{cases}
[x]原={x,1>x≥01−x,0≥x>−1
解释
这里讨论的是纯小数。
小数方面我们是使用小数点来作为符号位和数值位的分隔符的。譬如
−
0.101
-0.101
−0.101的原码表示就是
1.101
1.101
1.101请注意小数点前面的1表示的是符号的意思。
首先正数自然很好理解,不作解释。关于负数作少许解释,思想与正数类同。首先举例子:
−
0.101
-0.101
−0.101直观写出原码便是
1.101
1.101
1.101毋庸置疑。那么怎么用数学式子来求解呢?与上面相同我们考虑先将
−
0.101
-0.101
−0.101添个符号让其变成正的,然后加1变得到结果咯。再将这个思想推广为一般方法就得到上述的式子了。
注意要点
我们还是要讨论下0的小数原码。
可以预见0的小数原码还是有两种。
当0取0.00时,正数的原码为
0.00
0.00
0.00,负数的为
1.00
1.00
1.00。
总结
原码中:
[
0
+
]
原
≠
[
0
−
]
原
[0_+]_原\neq[0_-]_原
[0+]原=[0−]原
0的表示有两个
0
−
,
0
+
0_-,0_+
0−,0+。这也就产生了一定的浪费。
补码
补码的引入背景是很有意思的。我们可以从钟表中得到启示。因为太长,这里不做解释。一般的数电课本或者计算机组成原理课本上都会做引入解释,有兴趣的读者可以自行阅读。
补码整数表达式
[
x
补
]
=
{
0
,
x
2
n
≥
x
≥
0
2
n
+
1
+
x
0
>
x
≥
−
2
n
(
m
o
d
2
n
+
1
)
[x_补]=\begin{cases} 0,x \quad 2^n\geq x \geq0\\ 2^{n+1}+x \quad 0>x\geq-2^n(mod 2^{n+1}) \end{cases}
[x补]={0,x2n≥x≥02n+1+x0>x≥−2n(mod2n+1)
解释
一般而言要得到一个负数的补码,只要用模去加上这个数就行了。
注意
1.这里的模是数值部分的位数n再加上1也就是n+1。为什么模要是
2
n
+
1
2^{n+1}
2n+1而不是
2
n
2^n
2n呢?举个例子来解释。比如
−
101
-101
−101如果用模3来求补码:
[
−
101
]
补
=
1000
−
101
=
0
,
011
[-101]_补=1000-101=0,011
[−101]补=1000−101=0,011这样就和正数的补码产生冲突了。所以我们用模
2
n
+
1
2^{n+1}
2n+1来求负数的补码。这个例子就是
[
−
101
]
补
=
10000
−
101
=
1
,
011
[-101]_补=10000-101=1,011
[−101]补=10000−101=1,011这样就符合了我们的理解了。
补码小数表达式
[
x
]
补
=
{
x
1
>
x
≥
0
2
+
x
0
>
x
≥
−
1
(
m
o
d
2
)
[x]_补=\begin{cases} x\quad 1>x\geq0\\ 2+x\quad 0>x\geq-1(mod2) \end{cases}
[x]补={x1>x≥02+x0>x≥−1(mod2)
解释
负数可能比较难理解。为什么是
2
+
x
2+x
2+x呢?
首先我们举个例子一个数值位有三位的小数x。
x
m
a
x
=
0.111
x_{max}=0.111
xmax=0.111与1差了0.001,但是我们直接用1去加的话就只能得到0.001这同样产生了冲突。所以要用2来加。
关于0的补码
我们以整数为例子。
[
−
0
]
补
=
100
−
000
=
100
[-0]_补=100-000=100
[−0]补=100−000=100舍去1也就是00。
[
+
0
]
补
=
0
[+0]_补=0
[+0]补=0
所以
[
−
0
]
补
=
[
+
0
]
补
[-0]_补=[+0]_补
[−0]补=[+0]补
这样补码就可以多表示一位负数。也就是上一篇文章(开头有上一篇链接)为什么int的表示范围,负数比整数多一个的原因了。
反码
反码就比较容易了。他就是把原码的每一位取反。这里也给出数学表达式,有了前面补码和原码的学习,反码的数学表达式易如反掌。
反码整数表达式
[
x
]
反
=
{
0
,
x
2
n
>
x
≥
0
(
2
n
+
1
−
1
)
+
x
0
≥
x
>
−
2
n
[x]_反=\begin{cases} 0,x\quad 2^n>x\geq0\\ (2^{n+1}-1)+x \quad 0\geq x>-2^n \end{cases}
[x]反={0,x2n>x≥0(2n+1−1)+x0≥x>−2n
反码整数表达式
[ x ] 反 = { 0 , x 1 > x ≥ 0 ( 2 − 2 − n ) + x 0 ≥ x > − 1 ( m o d ( 2 − 2 − n ) ) [x]_反=\begin{cases} 0,x\quad 1>x\geq0\\ (2-2^{-n})+x \quad 0\geq x>-1 (mod(2-2^{-n})) \end{cases} [x]反={0,x1>x≥0(2−2−n)+x0≥x>−1(mod(2−2−n))
原码、补码、反码 转换方式 。
原码-补码
①每位取反 ②末位+1
不管是整数还是小数 原码到补码,补码到原码都可以这么算。读者可自行验算几个码。
原码-反码
每位取反,反之亦然。
补码-反码
末位减一,反之末位加一