首页 > 其他分享 >移位运算

移位运算

时间:2023-04-30 22:14:28浏览次数:29  
标签:右移 逻辑 运算 符号 int 算术 移位 converter

概述

这里以C语言为例描述移位运算的行为。 对于一个位表示为 \(x_{w-1}\), \(x_{w-2}\) ,..., \(x_{0}\) 的操作数 x, C 表达式 \(x << k\) 会生成一个値,其位表示为 \([\) \(x_{w-k-1}\), \(x_{w-k-2}\) ,..., \(x_{0}\),0,... , 0 \(]\) 。也就是说,x 向左移动 k 位,丢弃最高的 k 位,并在右端补 k 个 0。移位量应该是一个 0 ~ w - 1 之间的值。移位运算是从左至右可结合的,所以 \(x << j << k\) 等价于 \((x << j) << k\)。

有一个相应的右移运算 \(x>>k\),但是它的行为有点微妙。一般而言,机器文持两种形式的右移: 逻辑右移和算术右移。逻辑右移在左端补 k 个零,得到的结果是 \([\) 0 , ... , 0 , \(x_{w-1}\),\(x_{w-2}\) , ... ,\(x_k\) \(]\)。算术右移是在左端补 k 个最高有效位的值,得到的结果是 \([\) \(x_{w-1}\), ..., \(x_{w-1}\), \(x_{w-1}\),\(x_{w-2}\), ..., \(x_k\) \(]\)。这种做法看上去可能有点奇特,但是我们会发现它对有符号整数数据的运算非常有用。

让我们来看一个例子,下面的表给出了对一个8位参数 × 的两个不同的值做不同的移位操作得到的结果:

操作
参数x [011000111] [100101011]
x << 4 [00110000] [01010000]
× > 4 (逻辑右移) [00000110] [000010011]
x>>4 (算术右移) [00000110] [11111001]

可以看到除了一个条目之外,其他的都包含填充0。唯一的例外是算术右移 [10010101] 的情况。因为操作数的最高位是1,填充的値就是1。
C语言标准并没有明确定义对于有符号数应该使用哪种类型的右移——算术右移或者逻辑右移都可以。不幸地,这就意味着任何假设一种或者另一种右移形式的代码都可能会遇到可移植性问题。然而,实际上,几乎所有的编译器/机器组合都对有符号数使用算术右移,且许多程序员也都假设机器会使用这种右移。另一方面,对于无符号数,右移必须是逻辑的。

与C相比,Java 对于如何进行右移有明确的定义。表达是 \(x>>k\) 会将 × 算术右移 k 个位置,而 \(x >>> k\) 会对 × 做逻辑右移。

逻辑右移

在 C/C++ 中如果要对有符号数进行逻辑右移,那么不能简单的使用 x >> k,因为对于负数会用符号位填充左端的 k 位。因此要进行逻辑右移,我们使用一个数来记录前 k 位,使其前 k 位都是0,其余都是1,然后与 x >> k 的结果做与运算。

// 由于无符号数右移一定是逻辑右移,因此先转换为无符号数,得到前k位都是0,然后再转换为有符号数
int logic_r_shift(int x, int k) {
    return (int)((unsigned int)x >> k);
}

网上还流传有另一种写法:

// mask 得到一个前 k 位都是0的数,但是由于 >> 的运算符对于有符号数在C中并没有明确定义(即使大部分编译器都使用了算数右移)
// 所以即使以下代码可以正常运行,但并不保证没有可移植问题
int logical_right_shift(int x, int k)
{
    int size = sizeof(int) * 8; // usually sizeof(int) is 4 bytes (32 bits)
    int mask = ~(((0x1 << size) >> k) << 1)
    return (x >> k) & mask;
}

C++中可以通过模板函数和 union 的结合实现一个通用的逻辑右移运算。

template <typename T, typename P>  
union Converter {  
    static_assert(sizeof(T) == sizeof(P), "size not match");  
    T first;  
    P second;  
};

static inline uint32_t Int32ToUInt32(int32_t v) {  
    Converter<int32_t, uint32_t> converter;  
    converter.first = v;  
    return converter.second;  
}  
  
static inline int32_t UInt32ToInt32(uint32_t v) {  
    Converter<int32_t, uint32_t> converter;  
    converter.second = v;  
    return converter.first;  
}

static inline int32_t logicalRightShift32(int32_t value, uint32_t spaces) {  
    return UInt32ToInt32((Int32ToUInt32(value) >> spaces));  
}

标签:右移,逻辑,运算,符号,int,算术,移位,converter
From: https://www.cnblogs.com/ZhaoxiCheung/p/17365840.html

相关文章

  • C语言打印上下金字塔的按位取反运算符的精妙用法
    在打印上下金字塔的通常语句用法应该都是像下面这种#include<stdio.h>intmain(){  intn; do{   for(inti=1;i<n;i++){     for(inta=0;a<n-i;a++){       printf("");     }    for(intj=0;j<2*i-1;j++){     ......
  • java基础-算术运算符(加减乘除取余),隐式转换、强制转换
    一、运算符和表达式的定义运算符:对字面量或者变量进行操作的符号。表达式:用运算符把自变量连接起来,符合java语法的式子就可以称为表达式。例如:inta=10;intb=20;intc=a+b;其中,+,是运算符,并且是算术运算符;a+b是表达式,由于+是算数运算符,所以这个表达式叫算术表达式。二、......
  • matlab学习1(基本操作、stringchar、矩阵运算、基础图)
    1.matlab简介matlab是矩阵实验室,数据是以矩阵的形式存在。2.基本操作1).直接在命令行输入指令2).在脚本文件章编写程序后运行脚本文件:存放代码的文件,尾缀:.m实时脚本文件界面方便,将结果实时显示在代码旁边(可以加代码,图片,类似于一个文档编辑器,很推荐使用)3).在函数文......
  • Debug Assertion Failed!:Expression: can't dereference out of range vector iterato
    1#include<iostream>2#include<vector>3usingnamespacestd;4boolFind(inttarget,vector<int>array){5autobegin=array.begin(),end=array.end(),mid=begin+(end-begin)/2;6while((target!=*mid)&&a......
  • [逻辑代数基础]#1 基本运算与复合运算
    基本运算运算表达式真值表与(AND)$A·B$或(OR)$A+B$非(NOT)$A'$、$\overline{A}$、$\simA$、$\negA$均可。出于便利的考虑。下文使用$A'$表示非运算。非运算优先级高于与或。复合运算运算逻辑表达式真值表与非/NAND$Y=(A·B)'=A'+B'$......
  • P4681 [THUSC2015]平方运算 题解
    题面链接简要题意给定一个序列,区间.map([](intx){x=x*x%p;});,区间求和。p给定,为小质数。\(N,M\le10^5\)。题解而把一个数看作一个点,向其平方取模连一条边,则最终必然构成一个基环森林,注意到\(P\)很小,每个数经过\(11\)次迭代之后就会进入环中。对于一个区间,如......
  • Java算数运算符(++和--)
    1.++和--单独使用就是自增和自减i++-->i=i+1++i-->i=i+1i---->i=i-1--i-->i=i-12.++和--作为表达式使用j=++i-->先自增后赋值-->i=i+1;j=ij=i++-->先赋值后自增-->j=i;i=i+1j=--i-->先自减后赋值-->i=i-1;j=ij=i---->先......
  • LeetCode 241 为运算表达式设计优先级
    LeetCode|241.为运算表达式设计优先级  给你一个由数字和运算符组成的字符串 expression,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以按任意顺序返回答案。  生成的测试用例满足其对应输出值符合32位整数范围,不同结果的数量不超过104。示......
  • python逻辑运算 and、or
    and运算符xandyand两端的操作数,如果左侧已知为False的话,则不判断右侧,并以左侧操作数的值作为整体表达式的值and两端的操作数,如果左侧判断为True的话,则继续判断右侧,并以右侧操作数的值作为整体表达式的值1and2and3#31and0and3#0   直到找到0跳出,否则一直找到......
  • 运算符重载
    一.问题描述:请定义一个分数类,拥有两个整数的私有数据成员,分别表示分子和分母(分母永远为正数,符号通过分子表示)。重载运算符加号"+",实现两个分数的相加,所得结果必须是最简分数。输入:第一行的两个数分别表示第一个分数的分子和分母(分母不为0)。第二行的两个数分别表示第二个......