可变位宽的符号扩展:
有时,我们需要扩展数字的符号位,但是我们不知道该数字的总位数,如果用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;