二进制中原码、反码、补码以及如何计算补码,附力扣算法题
创始人
2025-05-28 02:00:37

二进制

二进制和十进制一样,也是一种进位计数制,但是它的基数是 2。二进制表达式中 0 和 1 的位置不同,它所代表的数值也不同。例如,二进制数 0000 1010 表示十进制数 10。一个二进制数具有两个基本特点:两个不同的数字符号,即 0 和 1,逢二进一。

  • 十进制与二进制数之间的转换
    用计算机处理十进制数时,必须先把它转化为二进制数才能被计算机所接受;同理,计算结果应该将二进制数转换成人们习惯的十进制数。

  • 十进制转换成二进制
    把一个十进制转换为二进制的方法是:把被转换的十进制数反复地除以 2,直到商为 0 为止,所得余数(从末位读起)就是这个数的二进制表示,简单地说,就是 “除 2 取余法”。
    在这里插入图片描述

  • 二进制转十进制
    要把二进制转换为十进制数,只要将二进制数按权展开求和即可。
    在这里插入图片描述

二进制中码的概念

1、原码:

一个正数,按照绝对值大小转换成的二进制数;一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。
比如 00000000 00000000 00000000 00000101 是 5的 原码。
10000000 00000000 00000000 00000101 是 -5的 原码。

备注:
比如byte类型,用2^8来表示无符号整数的话,是0 - 255了;如果有符号, 最高位表示符号,0为正,1为负,那么,正常的理解就是 -127 至 +127 了.这就是原码了,值得一提的是,原码的弱点,有2个0,即+0和-0(10000000和00000000);还有就是,进行异号相加或同号相减时,比较笨蛋,先要判断2个数的绝对值大小,然后进行加减操作,最后运算结果的符号还要与大的符号相同;于是,反码产生了。

2、反码

正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反[每一位取反(除符号位)]。
取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)
比如:正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101
负数10000000 00000000 00000000 00000101 的反码则是 11111111 11111111 11111111 11111010
反码是相互的,所以也可称:10000000 00000000 00000000 00000101 和 11111111 11111111 11111111 11111010互为反码。

备注:还是有+0和-0,没过多久,反码就成为了过滤产物,也就是,后来补码出现了。

3、补码

正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1.
比如:10000000 00000000 00000000 00000101 的补码是:11111111 11111111 11111111 11111010。
那么,补码为:
11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011

备注:1、从补码求原码的方法跟原码求补码是一样的 ,也可以通过完全逆运算来做,先减一,再取反。
2、补码却规定0没有正负之分

所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。

Java中如何计算

  • 如果计算反码?
  • 如何计算补码?
  • 如何输出二进制字符串?
  • 不使用"除2取余法"如何计算二进制串?

下面代码是上述问题的解答(简单写了个程序,肯定不是最优解,但适合讲解,细节可以自行优化)

二进制中1的个数

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。

提示:

请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用 二进制补码 记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
示例 1:

输入:n = 11 (控制台输入 00000000000000000000000000001011)
输出:3
解释:输入的二进制串
00000000000000000000000000001011 中,共有三位为 ‘1’。

示例 2:

输入:n = 128 (控制台输入 00000000000000000000000010000000)
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:

输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3)
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
提示:

输入必须是长度为 32 的 二进制串 。

-2^32 < n < 2^32 - 1 也就是Integer.MIN_VALUE到Integer.MAX_VALUE的范围。二进制的表示中最高位表示符号,0为整,1为负。

public class hammingWeight {/**** @param n* @return*/public static int hammingWeight(long n) {if (Integer.MIN_VALUE == n) {return 1;}// 这里int是-2^32 < n < 2^32 -1 所以需要数组有32个元素来承接0或1,boolean true 表示1, false 表示 0,其中数组的最后一位元素用来保存二进制符号 boolean[] _1 = new boolean[32];// 这里定义缓存是为了防止重复计算,只有在第一次的时候进行次方运算Map cache = new HashMap<>();// 为什么取绝对值?因为负数要转换为正整数进行计算补码long sum = Math.abs(n);// 判断是否为负数boolean isPlus = n >= 0;// 统计1出现的次数int total = 0;while (sum != 0) {int count = 0;long pow = 0;  while (sum > pow) {Long aLong = cache.get(count);if (aLong == null) {pow = (long) Math.pow(2, count);cache.put(count, pow);System.out.println(count);} else {pow = aLong;}if (pow > sum) {sum -= pow / 2;_1[count - 1] = true;break;} else if (pow == sum) {sum -= pow;_1[count] = true;break;} else {count ++;}}}if (!isPlus) { // 处理补码// 正整数printBinary("正整数", _1);// 取反for (int i = 0; i < _1.length; i++) {if (_1[i]) {_1[i] = false;} else {_1[i] = true;}}printBinary("取反", _1);// + 1if (_1[0]) {for (int i = 0; i < _1.length - 1; i++) {if (_1[i]) {_1[i] = false;} else {_1[i] = true;break;}}} else {_1[0] = true;}_1[_1.length - 1] = true;printBinary("+1", _1);}for (boolean b : _1) if (b) total++;return total;}public static void printBinary (String name, boolean[] arr) {StringBuilder stringBuilder = new StringBuilder();arr2List(arr).forEach(obj -> {if (obj) stringBuilder.append("1");else stringBuilder.append("0");});System.out.println(name + ":" + stringBuilder.toString());}public static List arr2List (boolean[] arr) {List bo = new ArrayList<>();for (int i = arr.length - 1; i >= 0; i--) {bo.add(arr[i]);}return bo;}public static void main(String[] args) {// 4294967293// 2147483647System.out.println((long) Math.pow(2, 31));int i = hammingWeight(-2147483648);System.out.println(i);//if (4294967293L > Integer.MAX_VALUE) {//    System.out.println("ok");//    System.out.println((long)Math.pow(2, 16));//    System.out.println((long)Math.pow(2, 32));//}}
}

核心思想

① 将10进制转二进制用一个boolean[]数组来承接,数组中元素 false表示0,true表示1。这样我们很容易遍历boolean数组就可以把二进制字符串表示出来。

②十进制计算二进制的核心算法就是判断n 是否大于2 ^ k,k表示次方。如果n == 2 ^ k则boolean数组b[k] = true,并且n = n - 2 ^ k次方。如果n < 2 ^ k 则b[k - 1] = true, 并且n = n - 2 ^ k / 2。如果n > 2 ^ k则k ++ 知道满足上述的两个条件。

③接着如果n为负数则求反码,根据反码再求补码

④遍历boolean数组统计true元素出现的次数就是本题答案。

⑤求反码很简单,只需要把true变成false,false变为true即可,求补码就需要考虑“进位”的问题,比如01 + 01 就需要进以为变成10,111 + 001 = 1000。1001 + 0001 = 1010。详细可以看上面代码如何实现。

总结

① 二进制中最高位表示符号位
② 负数来说反码就是原码非符号位取反,0 变成1,1变成0。对于正数来说就是反码就是原码不需要计算。
③ 负数来说补码就是反码 + 1,正数来说补码就是原码
④ 10进制转2进制的方法有很多,上述介绍了只介绍了两种

参考文章

负数的二进制表示方法(正数:原码、负数:补码)
Java 运算符

相关内容

热门资讯

重磅.来袭“ 欢乐贰柒拾辅助挂... 您好:欢乐贰柒拾这款游戏可以开挂,确实是有挂的,需要了解加客服微信【3398215】很多玩家在这款游...
必备教程" 微乐江西... 必备教程"微乐江西麻将到底真的有挂吗"(其实真的有挂)-必备您好:微乐江西麻将这款游戏可以开挂,确实...
重大通报“新道游拼三张到底有透... 您好:新道游拼三张这款游戏可以开挂,确实是有挂的,需要软件加微信【4194432】,很多玩家在新道游...
今日了解" 众竟娱乐... 您好:众竟娱乐这款游戏是可以开挂的,究竟有没有挂确实能开挂,了解请添加《3045033》(加我们微)...
科普实测“新战皇牛牛透视挂辅助... 您好:新战皇牛牛这款游戏可以开挂,确实是有挂的,需要软件加微信【4194432】,很多玩家在新战皇牛...