C++ 中的位移运算符

Anam Javed 2023年1月30日 2022年4月20日
  1. C++ 中的左位移位运算符
  2. C++ 中的右位移运算符
  3. C++ 中浮点数据类型的位移
  4. C++ 中数组的位移
  5. C++ 中的位移位和掩码
  6. C++ 中负数的位移
  7. 在 C++ 中使用 Long 进行位移
  8. 结论
C++ 中的位移运算符

在 C++ 中,位移运算符按照其名称的含义进行操作,即位移位。根据程序的要求,移位运算符将二进制位向左或向右移动。

整数值应用于这些运算符(int、long、可能是 short 和 byte 或 char)。在某些语言中,对小于 int 的任何数据类型使用移位运算符会自动将操作数的大小调整为 int。

本文将详细讨论 C++ 中的左移和右移运算符及其实现以及相关示例。

C++ 中的左位移位运算符

左移运算符将移位表达式中的位向左移动加法表达式中的位数。移位操作腾出的位位置用零填充,从末尾移出的位被丢弃,包括符号位。

左移运算符需要两个数字。这会移动第一个操作数的位,而第二个操作数决定要移位的位数。

你可以说将整数 a 与整数 b 左移,用 (a<<b) 表示,等效于将 a 乘以 2^b(2 的 b 次方)。左移运算符用 << 表示。

例如,M<<k。这里,M 是第一个操作数,k 是第二个操作数。

让我们取 M=33; 这是二进制的 100001 和 k = 2。如果 M 左移 2,表示为 M=M<<2,它将变为 M=M(2^2)

因此,M=33(2^2)=132 可以写成 10000100。

例子:

#include <iostream>
using namespace std;

int main()
{
    unsigned char x = 6, y = 7;
    cout <<"x<<1 = "<< (x<<1) << endl;
    cout <<"y<<1 = "<< (y<<1) << endl;
    return 0;
}

输出:

x<<1 = 12
y<<1 = 14

在上面的代码中,unsigned char xchar y 变量表示一个字符数据类型,其中变量使用所有内存的 8 位,并且没有符号位(在有符号的 char 中存在)。

这里,char x 等于 6,即二进制的 00000110,而 char y 等于 7,即二进制的 00000111。

第一个 print 语句声明将 x 的值左移 1 位;结果是 00001100。第二个打印语句将 y 的值左移 1 位;结果是 00001110。

C++ 中的右位移运算符

右移运算符将移位表达式中的位模式移动加法表达式向右提供的位数。对于无符号值,移位操作腾出的位位置是零填充的。

符号位替换有符号数中的空位位置。如果数字为正,则使用值 0;如果数字为负数,则使用值 1。

右移运算符需要两个数字。这会移动第一个操作数的位,而第二个操作数决定要移位的位数。

你可以说将整数 a 与整数 b 右移,表示为 (a>>b),相当于将 a 除以 2^b(2 的 b 次方)。右移运算符表示为:>>

例如,M>>k 。这里,M 是第一个操作数,k 是第二个操作数。

让我们取 M=32; 这是二进制的 100000 和 k = 2。如果 M 右移 2,表示为 M=M>>2,那么 M 将变为 M=M/(2^2)。因此,M=32/(2^2)=8 可以写成 1000。

示例程序:

#include <iostream>

int main()
{
    unsigned char x = 6, y = 9;
    cout <<"a>>1 = "<< (a >> 1)<< endl;
    cout <<"b>>1 = "<< (b >> 1) << endl;
    return 0;
}

输出:

x>>1 = 3
y>>1 = 4

在上面的代码中,unsigned char xchar y 变量表示变量中的字符数据类型,它使用了内存的所有 8 位,并且没有符号位(在有符号的 char 中存在)。

这里,char x 等于 6,即二进制的 00000110,而 char y 等于 9,即二进制的 00001001。

第一个 print 语句声明将 x 的值右移 1 位;结果是 00000011。第二个打印语句声明将 y 的值右移 1 位;结果是 00000100。

C++ 中浮点数据类型的位移

你不能在 C++ 中对浮点数进行位移,因为它会显示错误,但这是为什么呢?这是因为浮点数以特殊格式存储。

浮点数的 32 位分为两类:有效数和指数。移位可能会将位从指数类别转移到有效数字类别,反之亦然。

例子:

#include <stdio.h>

int main( int ar, char *arg[] )
{
    float testFl = 2.5;

    printf( "testFloat (before): %f\n", testFl );
    testFl = testFl << 1;
    printf( "testFloat (after): %f\n", testFl );
    return 0;
}

输出:

error: invalid operands to binary << (have 'float' and 'int')

右移或左移将折叠所有位。

C++ 中数组的位移

有一个大小为 n 的数组 ar[] 和一个整数 m

目标是通过对存在的所有数组元素执行右移操作来使所有数组元素 > m。如果你不能这样做,请打印 -1。

例子:

Input: ar[] = { 21, 22, 23, 19 }, m = 34
Output: { 26, 26, 27, 25 }

Explanation:
ar[0] = 10101
After 1 right shift, 11010 → 26
ar[1] = 10110
After 3 right shift, 11010 → 26
ar[2] = 10111
After  1 right shift, 11011 → 27
ar[3] = 10011
After 2 right shift, 11001 → 25

代码:

#include <bits/stdc++.h>
using namespace std;

int setBitNumber(int n)
{
    int m = log2(n);
    return m;
}

bool check(int ar[], int m, int n)
{
    for (int i = 0; i < n; i++) {
        if (ar[i] <= m)
            return false;
}
return true;
}

void modifyArray(int ar[], int m, int n)
{
for (int i = 0; i < n; i++) {
    if (ar[i] > m)
        continue;
    else {
       int bits = setBitNumber(ar[i]);
        int el = ar[i];
        for (int j = 0; j < bits; j++) {
            if (el & 1) {
                el >>= 1;
                el |= (1 << bits);
            }
            else {
                el >>= 1;
            }
            if (el > m) {
                arr[i] = el;
                break;
            }
        }
    }
}

if (check(ar, m, n)) {
    for (int i = 0; i < n; i++)
        cout << ar[i] << " ";
}
else
    cout << -1;
}

int main()
{
    int ar[] = { 21, 22, 23, 19 };
    int n = sizeof(ar) / sizeof(ar[0]);
    int m = 24;
    modifyArray(ar, m, n);
    return 0;
}

输出:

[26, 26, 27, 25]

程序中执行的主要操作是数组的遍历。它对数组 ar[i] 的每个元素进行右移操作。

如果 ar[i] > m,则检查条件。如果为真,则更新数组 ar[i],否则继续。

如果数组 ar[i] ≤ m 的任何元素,则打印-1,否则打印数组 ar[i]

C++ 中的位移位和掩码

掩码指定应保留哪些位以及应清除哪些位。

例子:

Mask:   00001111b
Value:  01010101b

当我们对值应用掩码时,我们希望清除前(高)四位,同时保留最后(低)四位。结果,我们检索到了底部的四位。

输出:

Mask:   00001111b
Value:  01010101b
Result: 00000101b

位移运算符经常与掩码操作一起使用,以将位从一个数字中逐一剥离。以下示例说明了如何将 unsigned char 划分为单独的位数组。

unsigned char y = 0xD5;
unsigned char bit[8];
unsigned char mask = 1;
for(int x = 7;x >= 0;x--) {
    bits[x] = y & mask;
    y = y >> 1;
}

C++ 中负数的位移

不应使用左右移位运算符输入负数。如果任一操作数是负整数,则结果是未定义的行为。

例如,1 >> -11 << -1 的结果都是未定义的。

#include <iostream>

int main()
{
    unsigned char x = -6,
    cout <<"a>>1 = "<< (a >> 1)<< endl;
    return 0;
}

输出:

error: undefined behavior in C

在 C++ 中使用 Long 进行位移

数据类型 long 用于位移 32 位或 64 位。

例子:

对于 32 位,

unsigned long A = (1L << 37)

对于 64 位,

unsigned long long A = (1ULL << 37);

使用程序实现以下内容:

#include <stdio.h>

int main(void)
{
    long long y = 1ULL;

    // Left shift 40 times
    y <<= 20;
    y <<= 20;

    printf("y is %lld\n", y);
    return 0;
}

输出:

y is 1099511627776

这里,取一个 64 位变量 long long y,而 1ULL 是一个无符号 long long int 常量(64 位)。变量 y 移动 40 次并打印出来。

结论

在本文中,我们讨论了 C++ 中的位移位运算符。我们详细了解了 C++ 中的左右移位运算符。

相关文章 - C++ Operator