原码,反码,补码 是计算机 方便计算的一种方式。
首先问,为什么有这个概念?
现代计算机,都用二进制 表示实数 (包括正数,负数,浮点数等),在计算的时候,势必会涉及到正负符号的问题。例如 -1 在计算机 如何表示。如果要让计算机在计算的时候区分 操作数的符号,那么势必会极大增加 计算机的电路设计复杂度。所以设计了反码,补码的概念。
什么是 原码,反码,补码,它们之间是什么关系?
原码 :最简单的表示方式,直接使用最高位表示符号,其余位表示数值。但是原码有一个问题,就是0有两个表示形式(+0和-0),并且在进行加减运算时需要额外的处理符号位,增加了运算的复杂性。
反码: 为了解决原码中0的符号问题,反码将正数的表示方式与原码相同,而负数的表示方式是将对应正数的所有位取反。但是反码表示仍然存在两个零的问题,并且在加减运算时同样需要额外的处理。
补码:补码是目前最广泛使用的表示有符号整数的方式。补码规定,正数的补码与其原码相同,负数的补码是其反码加1。补码表示只有一个零,并且加减法可以统一处理,无需额外的符号位处理。
补码的设计使得计算机可以使用相同的加法器进行加法和减法运算,简化了运算电路的设计。同时,补码还具有直观的数学性质,例如在补码表示中,减法可以看作加法的逆运算,这样就避免了额外的减法运算器。这些优点使得补码成为了计算机中表示有符号整数的主要方式。
对于正数, 原码,反码和补码,都是一样的二进制表示方式
对于负数,反码 = 原码的非符号位按位取反; 补码 = 反码+1;
举例: 在8位系统中 3 可以这样表示 : [0000 0011] 原 = [0000 0011] 反= [0000 0011] 补
[-3] = [1000 0011] 原 = [1111 1100]反 = [1111 1101] 补
在实际编程(C/C++)中,cpu在进行计算时,如何区分正数,负数,以便于在进行加法计算前转换成 补码呢?
如果是在编译前能确定 正负值的,由编译器直接将其转换成补码,例如一个全局变量 int8 a = -2;
在编译时就转换成了补码。 如果 值是在 程序运行后,由用户输入的,那么就要小心了,输入的值
需要考虑是否在变量类型定义的范围,否则可能会发生数据溢出问题。例如:
int main()
{
unsigned int8 a;
int8 b;
cin>> a <<endl;
cin>> b <<endl;
return ;
}
变量a 的输入必须是0-255 范围的值,变量b输入的值必须是 -128~127 之间,否则就会产生溢出。
无符号整型的溢出问题
当变量 a 输入了一个负数时,会发生溢出,具体过程如下
比如 用户输入 a = -3, 那么程序将自动把 -3的补码 [1111 1101] 当成无符号整数 赋值给 变量a
也就是a = 253.
混合数据类型的隐式转换问题:
c/c++中对此事的一些基本原则:
- 如果一个操作数是无符号整数,另一个操作数是带符号整数,则编译器会将带符号整数提升为无符号整数。
- 如果一个操作数是无符号整数,另一个操作数是浮点数,则编译器会将无符号整数转换为浮点数。
- 如果一个操作数是带符号整数,另一个操作数是浮点数,则编译器会将带符号整数转换为浮点数。
- 如果一个操作数是浮点数,另一个操作数是双精度浮点数,则编译器会将浮点数转换为双精度浮点数。
详情请 进入链接: https://www.cnblogs.com/MinPage/p/14117237.html
温故而知新!
最后出一道题检验一下,你是否理解了
#include <iostream>
using namespace std;
int main()
{
unsigned int8 a = 2;
int8 b = -5;
if(a+b)
{
cout<< "true" << endl;
}else
{
cout<< "false"<<endl;
}
}