1 ordinary c language level
#define avg2(a,b) ((a+b+1)>>1)
#define avg4(a,b,c,d) ((a+b+c+d+2)>>2)
显而易见...,注意a,b宏表达式可能引出的副作用
2 SIMD by software
实现方法1:
inline static uint64_t BYTE_VEC(uint64_t x)
{
x |= x << 8;
x |= x << 16;
x |= x << 32;
return x;
}
static inline uint64_t avg2_no_rnd(uint64_t a, uint64_t b)
{
return (a & b) + (((a ^ b) & BYTE_VEC(0xfe)) >> 1);
}
static inline uint64_t avg2(uint64_t a, uint64_t b)
{
return (a | b) - (((a ^ b) & BYTE_VEC(0xfe)) >> 1);
}
实现方法2:
#define op_avg_round(a,b) a = ( ((a)|(b)) - ((((a)^(b))&0xFEFEFEFEUL)>>1) )
#define op_avg_noround(a,b) a = ( ((a)&(b)) + ((((a)^(b))&0xFEFEFEFEUL)>>1) )
通过软件实现 singl instruction multi data,单指令多数据流,上述实现方法一样方法1实现8个8bits宽度数据的同时平均,在64位cpu上使用方法2实现4个8bits宽度数据的同时平均,在32位cpu上使用,简单对此加以分析加法结果有2个成分,1个是进位,1个是逻辑和((a)&(b))<<1是进位(((a)^(b))是逻辑和((a)&(b))<<1 + (((a)^(b))&0xFEFEFEFEUL) 为和,各自右移一位得到平均值,之所以是0xFE..,因为把每个字节的最后一个bit置零以免移位时进入下一个字节影响下一个字节的值((a)|(b)) 对应位在 0 1, 1 0, 1 1的3种情况下都得到1,所以((a)|(b))<<1 表示进位+非满进位,因为在0 1, 1 0这种情况下也产生了进位,刚好是它的逻辑和,其他分析同上
3 machine instruction levelAMD
3DNOW 指令:
#define AVG_3DNOW_OP(a,b,temp, size) /
"mov" #size " " #b ", " #temp " /n/t"/
"pavgusb " #temp ", " #a " /n/t"/
"mov" #size " " #a ", " #b " /n/t"
intel MMX指令:
#define AVG_MMX2_OP(a,b,temp, size) /
"mov" #size " " #b ", " #temp " /n/t"/
"pavgb " #temp ", " #a " /n/t"/
"mov" #size " " #a ", " #b " /n/t"