原码:
正整数的原码:这个数的二进制,符号位为0;正整数的原码=补码=反码
例1:+66
66的二进制:1000010,所以+66的原码: 0 1000010 =补码: 0 1000010=反码: 0 1000010
负整数的原码:仍是这个数的二进制,符号位为1;负整数的原码、反码、补码计算:先求原码,再求反码,最后求补码;
原码转换为反码:符号位不变,数值位按位取反;
原码转换为补码:符号位不变,数值位按位取反,末尾在+1;
例2:-66
66的二进制:1000010,所以-66的原码:1 1000010 补码:1 0111101 反码:1 0111110
二、二进制原码、反码、补码的加减运算及标志位
1补码加减基本公式
加法:
整数 [A]补+[B]补=[A+B]补 (mod 2n+1)
小数 [A]补+[B]补=[A+B]补 (mod 2)jianfa
减法:
整数 [A-B]补=[A]补+[-B]补 (mod 2n+1)
小数 [A-B]补=[A]补+[-B]补 (mod 2)
2标志位
CF(Carry Flag) : 进为标志位。主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。在8位二进制中,如果计算的结果超过 [0,255] 的范围,就有进位,CF就被置为1,如果结果再 [-128,127] 范围内,就是没有进位CF被置为0。
OF(Overflow Flag) :溢出。用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。在8位二进制中,如果一个运算的结果最终超过 [-128,127] 无论是大于127还是小于-128就被认为是溢出,OF被置为1,如果结果在 [-128,127] 就认为没溢出OF被置为0。
SF(Sign Flag) :符号标志。用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。
ZF(Zero Flag) :零标志。用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
PF(Parity Flag) :奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。
AF(Auxiliary Carry Flag) :辅助进位标志。在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:(1)、在字 *** 作时,发生低字节向高字节进位或借位时;(2)、在字节 *** 作时,发生低4位向高4位进位或借位时。
在计算机系统中,数值,一律采用补码表示和存储。
这就是说,计算机中,并没有原码和反码。
原码和反码,只是在求补码时,表现一下存在感而已。
但是,求补码,还有更正规的方法,完全可以不经过原码反码,就求出补码。
由补码,再求其代表的数值,也可以不用原码反码。
那么,就可以说,原码和反码,都没有任何用处。
-----------------------
补码,是什么呢?
其实,补码,就是一个“代替负数做运算”的正数。
使用了补码,计算机中就没有负数了,也就没有减法了。
那么,计算机只需要一个加法器,就可以走遍天下了。
补码的用处之一,就是简化计算机的硬件。
-----------------------
补码(也就是正数),怎么就能代表负数呢?
其实,道理也很简单。
你看 2 位 10 进制数吧:
25 - 1 = 24
25 + 99 = (一百) 24
进位是 10^2 = 100,这也是 2 位数的计数周期。
这个进位,显然不在 2 位数之中,那就舍弃吧。
只取 2 位数的结果,+99 和-1 的作用,就是相同的。
只要舍弃了进位,正数,就可以代替负数。
这个正数,就是“负数的补数”。
求补数的公式: 补数 = 负数 + 周期。
-----------------------
在三角函数中,大家都知道:
-π/2 和 +3π/2,这两个角度,功能也是相同的。
负角度,和正角度,要怎么变换呢?
也是用这样的公式: 正角度 = 负角度 + 周期(2π)。
-----------------------
计算机用二进制,补数,就改称为:补码。
8 位 2 进制是:0000 0000~1111 1111 (十进制 255)。
其计数周期是:2^8 = 256。
此时,-1 就可以用 255 (1111 1111) 代替。
同理,-2 的补码就是 254 (1111 1110)。
。。。
正数,本身就是正数,必须直接参加运算,不许再作任何变换。
所以,正数,根本就没有补数(补码)。
以上就是“求补码的正规做法”。
从中可以看到,并没有使用原码和反码,就把补码求出来了。
-----------------------
示例,5 - 7 = -2,用补码计算如下:
5= 0000 0101
-7 的补码 = 1111 1001
-相加-------------
得: (1) 1111 1110 = -2 的补码
舍弃进位,只取 8 位,结果就是正确的。
借助于补码,就可以用加法,实现减法运算。
原码和反码,都没有这种功能。
所以,在计算机中,根本就不使用原码和反码。
那么,原码和反码是什么呢?
它们只是老师讲课的资料而已,实际上,它们什么都不是。
原码:原码是二进制数字的一种简单的表示法。二进制首位为符号位,1代表负,0代表正。
反码:反码可由原码得到。如果是正数,反码与原码相同;如果是负数,反码是其原码(符号位除外)各位取反而得到的。
补码:补码可由原码得到。如果是正数,补码与原码相同;如果是负数,补码是对其原码(除符号位外)各位取反,并在末位加1而得到的(有进位则进位,但不改变符号位)。
python有按位取反的 *** 作符:~ 但是对负整数要小心 *** 作,因为在计算机系统中,数值一律用补码来表示和存储的。
#include<stdioh>
#include<stdlibh>
#include<mathh>
#include<conioh>
void convert(int num);
void oppose(int n);
int a[16];
void main(void)
{
int num,jdz;
char ans;
while(1)
{
printf("请输入任意一个十进制整数: ");
scanf("%d",&num);
printf("\n");
printf("其绝对值为: ");
jdz=abs(num);
printf("%d\n\n",jdz);
printf("其原码为: \n");
convert(jdz);
printf("\n\n");
if(num>=0)
{
printf("其补码为: \n");
convert(jdz);
printf("\n\n");
}
else
{
printf("其补码为: \n");
oppose(a[16]);
printf("\n\n");
}
printf("按回车键继续或按ESC键结束程序!!!\n");
ans=getch();
while(ans!=13 && ans!=27)
{
ans=getch();
}
if(ans==13) system("cls");
if(ans==27)
{
system("cls");
printf("谢谢使用!!!\n");
break;
}
}
}
void convert(int num) /定义转化为原码的函数/
{
int i;
a[0]=num%2;
for(i=1;i<=15;i++)
{
a[i]=(num/2)%2;
num/=2;
}
for(i=15;i>=0;i--)
printf("%2d",a[i]);
}
void oppose(int n) /定义转化为补码的函数/
{
int i;
for(i=0;i<=15;i++)
{
switch(a[i])
{
case 1:a[i]=0;break;
case 0:a[i]=1;break;
}
}
for(i=0;i<=15;i++)
{
a[i]++;
if(a[i]>1) a[i]=0;
else break;
}
for(i=15;i>=0;i--)
printf("%2d",a[i]);
}
在计算机中,使用二进制表达数字,例如,一个字节(8位)可表示的范围是0到255(在不考虑符号的情况下),即00000000到11111111。
考虑到数字有正负,我们第一时间想到,空出一位来表示符号位,例如0表示正,1表示负。则理论上我们表示的范围是-127到+127。这种表达 方式简单明了,好理解,但是有如下几个缺点:
在介绍补码之前,我们先来看看几个相关的概念,第一个就是原码
以一个字节为例,例如:
原码表示有简单易懂的优点,但是原码的符号位不能直接参与运算,必须和其他位分开,这就增加了硬件的开销和复杂性。
上面是的定义和反码的计算方式,我们可以以一种简单的方式概括为:
一个数的反码为这个数的绝对值各位取反
反码码是数值存储的一种,多应用于系统环境设置,如linux平台的目录和文件的默认权限的设置umask,就是使用反码原理。
来到这边文章的重点了,在计算机里面,定点数既不是使用原码表示,也不是使用反码表示,而是使用 补码
百科解释如下
首先,我们阐述下补码的计算方式
例如
补码的特性
以-11举例
-11 原码为 10001011
-11 补码为 11110101
相加为10000000(高位溢出)=128,这个128即为8位定点数的模
这个也是补码的优势之一,原码和补码的转换,可以使用同一套规则,我们以一个负数为例
-11的原码为10001011
通过补码的规则转为之后为11110101,此为-11的补码
该补码再通过相同的规则转换为(11110101的反码加1),10001011
在原码里面,+0和-0的表示方式不同,运算和表达的时候需要增加一些额外的逻辑,在补码里面则没有这个烦恼,补码的+0和-0的表示方式均为00000000(以8位为例)
这也是补码的优势之一,这样可以简化电路逻辑,我们这里面举个简单的例子
11+(-2)
11的补码为00001011
-2的补码为11111110
直接相加加过为00001001=9
补码只是一种相对合理的编码方案。这个方案在负数的机器表示中解决了3个问题:
阮一峰博客
在计算机系统中,数值,一律用补码来表示和存储。
补码,其实,就是一个“代替负数进行运算”的正数。
使用了补码(正数)之后,在计算机中,就没有负数了。
随之而来的就是:减法运算,也都不存在了。
所以,借助于补码,计算机只需要配置一个加法器,就能走遍天下。
使用补码的目的,也就是:简化计算机的硬件。
而原码、反码,都没有这种功能,所以,计算机中,根本就不用它们。
原码和反码,只能在纸上写一写而已。
在计算机中,原码和反码,都是不存在的。
它们之间你怎么写,都没有关系,反正,都没有任何用处!
---------------------
补码(就是正数),怎么就能代替负数呢?
你看时针:倒拨 3 小时,可以用正拨 9 小时代替吧?
你看三角函数:-π/2、+3π/2,两者的函数值也是相同的吧?
10 进制数,如果限定只用 2 位 ,那么就会有:
25 - 1 = 24
25 + 99 = (一百) 24
如果忽略进位一百(10^2),+99 就可以代替-1。
上面所说的这些正数,就是“负数的补数”。
求补数的公式是: 补数(即正数)= 负数 + 周期。
正数,必须直接就参加运算,不可再做任何变换。
就是说:正数,本身就已经是正数了,它并不存在什么补数。
---------------------
计算机用二进制,补数,那就称为“补码”了。
8 位 2 进制的周期,是:2^8 = 256。
8 位 2 进制,总共可以组成 256 个代码。
用其中的一半(即 128 个)代表负数,就是:-1 ~ -128。
那么:
-1 的补码,就是:-1 + 256 = 255 = 1111 1111(二进制)。
-2 的补码是:-2 + 256 = 254 = 1111 1110。
。。。
-128 的补码,就是:128 = 1000 0000。
---------------------
至此,你就可以推出“补码的定义式”:
当 X >= 0, [ X ]补 = X; 零和正数不用变换。
当 X < 0,[ X ]补 = X + 2^n。 n 是补码的位数。
这是通用的公式。
在严谨一点的书上,都有这种公式,你去翻翻书吧。
---------------------
按照公式求补码,是极为简便的,而且还能理解补码的意义。
而且,反过来求(由补码求数值),也是很方便的。
实际上,你只要会“补码与数值”的互换,就够用了。
那么,没有必要学“原码反码取反加一符号位不变”了。
况且,原码和反码比补码,还少了一个数,取反加一,也无法使用。
当然,那些数学不好的老师,也只能使用这些“隔路”的花样。
---------------------
算式 5 - 7 =-2,计算机用八位补码计算如下:
5 = 0000 0101
[-7]补码 = 1111 1001
--相加-----------
得: (1) 1111 1110 = [-2]补码
舍弃了进位,结果,就是正确的。
---------------------
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)