用位运算实现有符号16bit数据clamp
在处理16 bit数据时,时常要将其他类型数据固定在16bit。
通常来说,在C语言中用一个if或者三目运算符就可以完成这个功能:
#define Limit16(a) ((a) > 0x7FFF ? 0x7FFF : ((a) < -0x8000 ? -0x8000 : (a)))
用位运算也可以巧妙实现此功能:
short clamp16(int sample) { if ((sample >> 15) ^ (sample >> 31)) { sample = 0x7FFF ^ (sample >> 31); } return sample; }
代码流程说明如下:
- 0 < sample <= 0x7FFF:
sample >> 15 为 0;
sample >> 31 为 0;
异或后为0,跳过if,return sample;
- sample > 0x7FFF:
sample >> 15 为 1;
这里的int假定为32位,sample >> 31 为 0;
进入if后,sample = 0x7FFF ^ 0 = 0x7FFF;
- -0x8000 <= sample < 0:
sample >> 15 为 0xFFFFFFFF(高位为1,右移补1),负数是以补码的形式存在,大于-0x8000的数,高16位为1;
sample >> 31 为 0xFFFFFFFF,异或为0;
直接return
- sample < -0x8000:
sample >> 15 为0xFFFFxxxx低16位不确定,不全为1,sample >> 31 为 0xFFFFFFFF;
异或后不为0,进入if;
sample = 0x7FFF ^ 0xFFFFFFFF = 0xFFFF8000; 0xFFFF8000为其补码,值为-0x8000;
虽然这样的代码可能不便于阅读,不过作为一种位运算技巧,了解一下还是挺不错的。