C语言中的位操作(6)可变位宽的符号扩展

 可变位宽的符号扩展:                                                                                                                               

 有时,我们需要扩展数字的符号位,但是我们不知道该数字的总位数,如果用b表示(或者我们可能会使用类似于java这样缺乏位域的语言编程)

unsigned b; // 表示数x的位数
int x;      //将这个b位数符号扩展到r位
int r;      // 保存r位数字
int const m = 1U << (b - 1); // 如果b固定,中间量可以提前计算

x = x & ((1U << b) - 1);  // (Skip this if bits in x above position b are already zero.)
r = (x ^ m) - m;

 上面的代码要求4种操作,但是当位宽是常量而不是变量的时候,只需要2种更快的方法,假设高位都已经为0.

一种不取决于x的高b位为0,稍快但是稳定性较差的方法如下:

int const m = CHAR_BIT * sizeof(x) - b;
r = (x << m) >> m;

采用3步操作可变位宽的符号扩展:                                                                                                                                                                                     

 以下的代码在某些机器上面可能会比较慢,取决于乘法与除法的,这种版本采用4步操作,如果你知道初始位宽:b,并且b>1 

你可以采用 r = (x * multipliers[b]) / multipliers[b],只用3步操作使用 来进行符号位扩展。

unsigned b; // b代表x的位数
int x;      // 将要转换为r的b位数x
int r;      //保存为结果r
#define M(B) (1U << ((sizeof(x) * CHAR_BIT) - B)) 
// CHAR_BIT=bits/byte
static int const multipliers[] = 
{
  0,     M(1),  M(2),  M(3),  M(4),  M(5),  M(6),  M(7),
  M(8),  M(9),  M(10), M(11), M(12), M(13), M(14), M(15),
  M(16), M(17), M(18), M(19), M(20), M(21), M(22), M(23),
  M(24), M(25), M(26), M(27), M(28), M(29), M(30), M(31),
  M(32)
}; //如果是64位系统,则相应增加
static int const divisors[] = 
{
  1,    ~M(1),  M(2),  M(3),  M(4),  M(5),  M(6),  M(7),
  M(8),  M(9),  M(10), M(11), M(12), M(13), M(14), M(15),
  M(16), M(17), M(18), M(19), M(20), M(21), M(22), M(23),
  M(24), M(25), M(26), M(27), M(28), M(29), M(30), M(31),
  M(32)
};//如果是64位系统,则相应增加
#undef M
r = (x * multipliers[b]) / divisors[b];

下面一种与之不同的非轻便方法,但是需要算术右移来维持符号位,它应该更快。

const int s = -b; // 或者:  sizeof(x) * CHAR_BIT - b;
r = (x << s) >> s;
原文地址:https://www.cnblogs.com/xueda120/p/3068212.html