Cal*_*ius 5 c bit-manipulation
我们正在编写一个模拟器,我们需要在该模拟器中传播右移信号。仿真系统使用2的补码。
我读到>>C中有符号整数的运算符是实现定义的。因此,我不能依靠它会在所有平台上产生正确位模式的事实。
这意味着我将需要使用位操作来重现算术右移,并且我将尽可能避免不必要的分支。
编辑:
回应评论:
“缺少的位是当在x >> y中的x中设置符号位时,OP需要定义什么结果是“正确的””
我基本上想重现SAR x86指令的行为。负数用2的补码表示。右移基本上也应意味着除以2即可得到负数。
这意味着对于以1开头的位模式。因此,对于1xxxxxxx,向右移位应为11xxxxxx。对于以0开头的位模式,因此0xxxxxxx右移应为00xxxxxx。因此,MSB是“粘性”的。没有定义超过字长的移位。
int s = -((unsigned) x >> 31);
int sar = (s^x) >> n ^ s;
Run Code Online (Sandbox Code Playgroud)
这需要 5 次按位运算。
编辑:正如 user16217248 所指出的,s也可以计算为int s = -(x<0);。对于下面的 godbolt 示例,编译器确实生成了相同的代码。
正如已经提到的,算术右移x >> n对应于除法x / 2**n。如果系统只支持逻辑右移,可以先将负数转换为正数,然后再将其符号复制回来sgn(x) * (abs(x)/2**n)。这相当于右移前后乘以+/-1sgn(x) * ((sgn(x)*x)/2**n)。
整数乘以 +/-1 可以用条件无分支否定s^(s+x)或来模拟(x^s)-s。当s是 时0,什么也没有发生并且x保持不变,因此与 1 相乘。当s是 时-1,我们得到-x,因此与 相乘-1。
代码片段的第一行-((unsigned) x >> 31)提取符号位。在这里,unsigned转换确保编译成逻辑右移(汇编中的 SHR)。因此,立即结果是 0 或 1,求反之后s是0或-1。
通过轮班前后的两次无分支否定,我们得到((s^s+x) >> n) + s ^ s。这将执行除法并将结果四舍五入到零(例如-5>>1 = -2)。然而,算术右移(汇编中的 SAR)会降低结果(即-5>>1 = -3)。为了实现这一行为,必须放弃该+s操作。
演示如下: https: //godbolt.org和https://onlinegdb.com/Hymres0y8。
PS:我到达这里是因为 gnuplot 只有逻辑转换。
Rak*_*ish -1
我在使用中没有看到任何主要问题>>,但如果你想做算术右移,那么你可以将数字除以幂2,x其中x是你想要做的右移量,因为将数字除以二是等效的到一个右移。
假设您想做a >> x。那么通过做也可以实现a / (int)pow(2,x)。pow(2,x)是数学幂,或者您也可以将其视为2幂x。