像素混合运算中乘66049实现位复制的数学原理是什么
像素混合代码中66049常数乘法优化的数学逻辑
这个优化本质是编译器对整数运算做了等价代数折叠,原理非常直白:
- 先拆解
h()函数的实际运算:对于已经和0xff做掩码、取值在0~255的输入x,x << 8 | x完全等价于x * 257。因为x只有低8位有效,左移8位就是乘256,此时结果的低8位全是0,和原x做按位或不会触发任何进位,和直接加x的结果完全一致——比如x=0xab,运算结果是0xabab,算下来就是171*257=43947,分毫不差。 - 把这个等价关系代回原始
g()函数的逻辑,就能直接推导出常数来源:- 函数第一步先取x、y的低8位得到
x0 = x & 0xff、y0 = y & 0xff,对应汇编里的两条movzx零扩展指令,不管输入的高位是什么,最终只保留0~255的有效通道值。 - 代入h()的等价式,
h(x0) * h(y0) = (257 * x0) * (257 * y0) = (257*257) * x0 * y0 - 算下257的平方:
257 * 257 = 66049,就是汇编里出现的那个立即数。
- 函数第一步先取x、y的低8位得到
很多人第一反应会担心运算顺序变了会不会有整数溢出导致结果不对,实际上完全不会:x0和y0最大都是255,x0y0的最大值是255255=65025,再乘66049的最大结果是66049 * 65025 = 4294836225,比32位无符号整数的上限2^32 -1 = 4294967295还小13万多,全程32位乘法不会出现溢出截断,结果和原始写法完全一致。后面的>>24右移操作两个版本没有任何区别,所以反编译出来的g_()和原始g()是100%等价的,没有任何精度损失。
这个优化属于编译器最常规的强度削减操作:把h函数里两次移位、按位或的操作(本质是两次乘257)合并成一次常数乘法,省掉了多余指令,运行速度更快。顺带说下这段代码本身是图像alpha混合的经典定点数技巧:把8位像素值扩展成高低字节相同的16位值相乘后取高8位,本质是用极快的乘法+移位替代了时钟周期很长的除以255整数除法,在早期CPU上性能差距能到5~10倍。
内容的提问来源于stack exchange,提问作者xiver77
相关产品推荐
相关产品推荐

