大家好,欢迎来到IT知识分享网。
今天我们来谈谈按位取反这件事。
简单来说,按位取反就是先将一个数写成其二进制表达形式,然后1变0,0变1。下面就让我们展开深入地讨论吧!
文章目录
一、预备知识:
1. 原码:
定义:
✨原码是一种用二进制表示有符号整数的编码方式。其中,最高位表示符号位,0为正,1为负。其余位是数值位,表示数值的绝对值。
- 举个“栗子”来说:
- 1的原码是:001 ;
- -1的原码是:101 ;
✨我们可以看出,互为相反数的两个数的原码,除了第一位的符号位不一样以外,其余位都相同。(那么,可能有聪明的小伙伴们就想到了0,是不是0也有两种表达方式呢?果然聪明!在原码中,0和-0的表示是不一样的。)
优缺点:
- ❤️优点:简单直观,易于理解和计算。
- 💔缺点:加减法运算复杂,需要考虑符号位的处理。-0多占了一个数的表达位置,导致原码也可表示的总数减少了1个。
✨那可能又有小伙伴要问了,一个数很多吗?哈哈,一个-0单单看起来不多,但是一群-0不就多了吗?(这就告诉了我们”人多力量大”的道理,一个人可以走得很快,但一群人才能走得更远)。另外,-0的存在还会带来一些其他的问题:比如1️⃣(0)+(-0)=?2️⃣ 0和-0哪个大?
😢怎么一个原码事这么多?烦呐!下面就让我们来看看更为合适的编码方式–补码。
2. 补码:
❤️计算机中存储数据时,通常采用补码编码方式。
定义:
✨补码也是一种用于表示有符号整数的编码方式。其中,最高位(最左侧位)是符号位,0表示正数,1表示负数。其余位是数值位。
- 对于正数,补码就是其二进制原码本身。(看来不讲原码还不能开补码),如:数值+3的补码就是0011。
- 对于负数,补码是其对应正数的原码的各位取反,末位加一,符号位取1。
优缺点:
- ❤️优点:
1️⃣加减法运算可以直接按位运算,无需特殊处理符号位。(相对原码来说更加方便)
2️⃣解决了原码中存在的正零和负零的问题。(-0的位置让给了最小的数)
3️⃣表示范围更加均衡。(补码的最小值的绝对值比最大值的绝对值多1) - 💔缺点:
1️⃣加减法时可能溢出。
2️⃣对称不明显。(看吧,上帝为你打开一扇窗的同时,也会为你关闭一扇门)
🐒当然,补码的知识宝库偌大无比,我现在只不过是揭开了其冰山一角,但对我们解决一般的问题来说,足够了。
二、按位取反:
✨将一个数的二进制表达的每一位取反,即0变为1,1变为0。取反符号用 "~" 表示。(从最低位(最右侧位)开始,逐位进行取反操作。)
例如,对于一个8位的二进制数,按位取反后的结果是0。(注意,这是补码的取反哦)
#include<stdio.h> int main(void) {
int a = 0b1; printf("%d", ~a); return 0; }
- 首先,a是一个
int类型,一般是4个字节(Byte),而一个字节是8位(8个bit),所以总共是32位。0b1是1的二进制表达,具体可以写为:00000000 00000000 00000000 00000001. - 下面我们对它进行取反操作,得:
,但它是一个补码,我们以%d的形式输出就要得到它的十进制表达(可以理解为真值),那么问题来了,补码怎么转换成真值呢?考虑到具体的定义过于枯燥乏味,所以我直接告诉你转换的方法:可以先将补码转换为机器数,而计算机中的机器数一般用原码来表示,所以问题就转化为了补码->原码。 - 将补码的符号位不变,其余各位取反,末位加一。(这好像和原码转补码有点类似啊!)也就是:
00000000 00000000 00000001+1---> 00000000 00000000 00000010,再转换成十进制整数就是-2。
2️⃣0的按位取反:(%d的形式输出)
#include<stdio.h> int main(void) {
printf("%d", ~0); return 0; }
2️⃣0的按位取反:(%u的形式输出)
#include<stdio.h> int main(void) {
printf("%u\n", ~0); printf("%lld", ((long long)1 << 32) - 1); return 0; }
咦❓为啥同样是0,但取反后的输出结果不一样呢?
%d:有符号十进制整数的输出 (signed int):-2 ^ 31 -- 2 ^ 31 - 1%u:无符号十进制整数的输出 (unsigned int) :0 -- 2 ^ 32 - 1
这个有无符号具体就体现在是否有符号位,有符号位就少一位数值位,没有符号位就都是数值位。
- 0的补码:
00000000 00000000 00000000 00000000 - ~0的补码:
三、拓展应用:
1. 巧求相反数:(不用-)
✨相反数相必大家都知道,1的相反数是-1,0的相反数是0,简单来说一个数的相反数就是再其前面加个-
那么,不用这种方法还可以求相反数吗?
哈哈😄,其实这个问题我们上面已经说过了,直接利用补码的定义,求一个数的相反数,就是各位取反,末位加一。即-x=~x+1
#include<stdio.h> int main(void) {
int x = -18; printf("%d的相反数是%d\n",x, ~x + 1); int y = 18; printf("%d的相反数是%d",y, ~y + 1); return 0; }
(当然了,要注意数据的溢出问题。)
思考:既然一个数x的相反数可以通过~x+1来得到,记为y
- 则y=~x+1 -> ~(y-1)=x,所以,求x的相反数也可以用 ~(x-1)
#include<stdio.h> int main(void) {
int x = 18; printf("%d的相反数是%d\n", x, ~(x-1)); int y = 18; printf("%d的相反数是%d", y, ~y + 1); return 0; }
2. 代替减法(不用-实现减法)
#include<stdio.h> int main(void) {
int a=1,b=2; printf("%d-%d=%d\n",a, b,a+~b+1); return 0; }
3. 代替加法(不用+实现加法)
✨给定两个int类型的正数,不用+实现加法。根据加法定义,加上一个数等于减去一个数的相反数。即:a + b = a - (-b) = a - (~b +1)=a - ~b - 1;
#include<stdio.h> int main(void) {
int a=1,b=2; printf("%d+%d=%d\n",a, b,a-(~b + 1)); return 0; }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/112553.html






