算法-二进制和位运算

一.二进制

(1).无符号数:

无符号数是一种数据表示方式,它只表示非负整数,即没有符号位,所有的位都用来表示数值大小。在 C++ 等编程语言中,常见的无符号类型有 unsigned intunsigned char 等。例如,一个 8 位的无符号整数 unsigned char 可以表示范围为 0255 的整数,而不像有符号的 char 可以表示 -128127 的范围。

对于一个无符号整数,可以使用除 2 取余法手动将其转换为二进制表示。以下是一个简单的 C++ 示例:

cpp 复制代码
#include <iostream>
#include <string>

std::string binaryRepresentation(unsigned int num) {
    std::string binaryStr;
    while (num > 0) {
        binaryStr = std::to_string(num % 2) + binaryStr;
        num /= 2;
    }
    return binaryStr;
}

int main() {
    unsigned int num = 10;
    std::string binary = binaryRepresentation(num);
    std::cout << binary << std::endl;  // 输出 "1010"
    return 0;
}

(2).有符号数:

计算机中一般利用补码表示法:

  • 对于正数,其补码与原码相同。
  • 对于负数,补码是在反码的基础上加 1。
  • 例如,对于一个 8 位的有符号整数:
    • +5 的补码表示为 00000101(与原码相同)。
    • -5 的补码
    • 表示为 11111011(反码 11111010 加 1)。

对于一个使用补码表示的有符号二进制数,将其转换为十进制数的步骤如下:

  1. 判断正负

    • 首先,观察补码的最高位(符号位)。如果最高位为 0,则该数为正数,直接将补码转换为十进制即可。
    • 如果最高位为 1,则该数为负数,需要先将补码转换为原码,再将原码转换为十进制。
  2. 正数的转换(原码和补码相同)

    • 对于正数,直接将二进制数按权展开求和,即从右到左用二进制位上的数字乘以 ( 从 开始,从右向左递增),然后将结果相加。
    • 例如,对于 8 位补码表示的正数 01011010,转换为十进制为:
  3. 负数的转换(从补码到原码)

    • 对于负数,先对补码取反(包括符号位),然后加 1,得到原码。
    • 再将原码按权展开求和,最后加上负号。
    • 例如,对于 8 位补码表示的负数 10101101
      • 先取反得到 01010010
      • 再加 1 得到原码 01010011
      • 转换为十进制为:-(0x27+1x2+0x25+1x24+0x23+0x22+1x21+1x2)=-83

二.位运算

位运算符是一种操作二进制位的运算符,它们直接对操作数的二进制表示进行操作。在大多数编程语言中,常见的位运算符包括:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)和右移(>>)。这些运算符通常用于对整数类型的数据进行操作,因为整数在计算机中是以二进制形式存储的。

(1)按位与&

  • 按位与运算符 & 对两个操作数的每个二进制位进行逻辑与操作。如果两个相应的二进制位都为 1,则结果为 1;否则,结果为 0。
  • 示例(C++):
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;  // 二进制表示为 0101
    int b = 3;  // 二进制表示为 0011
    int result = a & b;  // 结果为 0001,即十进制的 1
    cout << result << endl;  // 输出 1
    return 0;
}

(2)按位或|

    • 按位或运算符 | 对两个操作数的每个二进制位进行逻辑或操作。如果两个相应的二进制位中至少有一个为 1,则结果为 1;否则,结果为 0。
  • 示例(C++)
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;  // 二进制表示为 0101
    int b = 3;  // 二进制表示为 0011
    int result = a | b;  // 结果为 0111,即十进制的 7
    cout << result << endl;  // 输出 7
    return 0;
}

(3)按位异或^

  • 按位异或运算符 ^ 对两个操作数的每个二进制位进行逻辑异或操作。如果两个相应的二进制位不同,则结果为 1;如果相同,则结果为 0。
  • 示例(C++)
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;  // 二进制表示为 0101
    int b = 3;  // 二进制表示为 0011
    int result = a ^ b;  // 结果为 0110,即十进制的 6
    cout << result << endl;  // 输出 6
}

(4).按位取反~

    • 按位取反运算符 ~ 对操作数的每个二进制位取反,即 0 变为 1,1 变为 0。
  • 示例(C++)
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;  // 二进制表示为 0101
    int result = ~a;  // 结果为 1010,即十进制的 -6
    cout << result << endl;  // 输出 -6
    return 0;
}

(5)左移<<

  • 功能
    • 左移运算符 << 将左操作数的二进制表示向左移动右操作数指定的位数。右侧空出的位用 0 填充。
  • 示例(C++)
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;  // 二进制表示为 0101
    int result = a << 2;  // 结果为 010100,即十进制的 20
    cout << result << endl;  // 输出 20
    return 0;
}

(6)右移>>

  • 功能
    • 右移运算符 >> 将左操作数的二进制表示向右移动右操作数指定的位数。对于无符号整数,左侧空出的位用 0 填充;对于有符号整数,根据不同的编程语言和机器,可能用符号位填充(算术右移)或用 0 填充(逻辑右移)。
  • 示例(C++)
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;  // 二进制表示为 0101
    int result = a >> 1;  // 结果为 0010,即十进制的 2
    cout << result << endl;  // 输出 2
    return 0;
}
相关推荐
GIS小天8 分钟前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年7月4日第128弹
人工智能·算法·机器学习·彩票
oioihoii22 分钟前
C++11 forward_list 从基础到精通:原理、实践与性能优化
c++·性能优化·list
满分观察网友z26 分钟前
开发者的“右”眼:一个树问题如何拯救我的UI设计(199. 二叉树的右视图)
算法
m0_6873998430 分钟前
写一个Ununtu C++ 程序,调用ffmpeg API, 来判断一个数字电影的视频文件mxf 是不是Jpeg2000?
开发语言·c++·ffmpeg
森焱森2 小时前
无人机三轴稳定化控制(1)____飞机的稳定控制逻辑
c语言·单片机·算法·无人机
循环过三天2 小时前
3-1 PID算法改进(积分部分)
笔记·stm32·单片机·学习·算法·pid
Ronin3052 小时前
【C++】类型转换
开发语言·c++
闪电麦坤952 小时前
数据结构:二维数组(2D Arrays)
数据结构·算法
mrbone112 小时前
Git-git worktree的使用
开发语言·c++·git·cmake·worktree·gitab
凌肖战2 小时前
力扣网C语言编程题:快慢指针来解决 “寻找重复数”
c语言·算法·leetcode