我总是假设在执行(a % 256)
时,优化器自然会使用高效的逐位操作,就像我编写(a & 0xFF)
一样。
在编译器资源管理器gcc-6.2(-O3)上测试时:
// Type your code here, or load an example.
int mod(int num) {
return num % 256;
}
mod(int):
mov edx, edi
sar edx, 31
shr edx, 24
lea eax, [rdi+rdx]
movzx eax, al
sub eax, edx
ret
当尝试其他代码时:
// Type your code here, or load an example.
int mod(int num) {
return num & 0xFF;
}
mod(int):
movzx eax, dil
ret
我好像完全忽略了什么。有什么想法吗?
5条答案
按热度按时间5uzkadbs1#
这是不一样的,尝试
num = -79
,你会从两个操作得到不同的结果。(-79) % 256 = -79
,而(-79) & 0xff
是某个正数。使用
unsigned int
时,操作是相同的,代码也可能相同。**PS-**有人评论
它们不应该相同,
a % b
被定义为a - b * floor (a / b)
。这不是它在C、C++、Objective-C(即所有问题中的代码将编译的语言)中的定义。
9wbgstp72#
简短回答
-1 % 256
产生-1
,而不是255
,255
是-1 & 0xFF
。因此,优化将是不正确的。长答案
C++有
(a/b)*b + a%b == a
的约定,这看起来很自然。a/b
总是返回不带小数部分的算术结果(向0截断)。因此,a%b
与a
具有相同的符号或为0。除法
-1/256
得到0
,因此-1%256
必须是-1
才能满足上述条件((-1%256)*256 + -1%256 == -1
),这与-1&0xFF
是0xFF
明显不同,因此编译器无法按照您想要的方式进行优化。C++ standard [expr.mul §4] as of N4606中的相关章节规定:
对于整数操作数,
/
运算符产生丢弃任何小数部分的代商数;如果商a/b
可表示为结果的类型,则(a/b)*b + a%b
等于a
[...]。启用优化
然而,使用
unsigned
类型,优化将是完全正确的,满足上述约定:另请参见此。
其他语言
不同的编程语言对此的处理方式有很大的不同,您可以在Wikipedia上查找。
x8diyxa73#
由于C++11,如果
num
为负,则num % 256
必须为非正。因此,位模式将取决于系统上有符号类型的实现:对于负的第一自变量,结果不是提取最低有效8位。
如果在您的例子中
num
是unsigned
,那就另当别论了:这些天来,我几乎 * 期望 * 编译器作出优化,你引用。kgqe7b3p4#
我对编译器的推理没有心灵感应的洞察力,但在
%
的情况下,有必要处理负值(除法向零舍入),而在&
的情况下,结果总是低8位。sar
指令听起来像是“算术右移”,用符号位值填充空出的位。v09wglhw5#
正如其他人指出的那样:
如果你像我一样希望模运算实际上输出一个正整数,就像我转换色调的用例一样(HSV颜色空间)double其中1.0 == 360度通过乘以255.0到无符号字符,取地板,然后取模256。则&0xff是正确的优化。注意,我将255度视为360度,以适应本例中的unsigned char。
但这可能不是适合您的特定用例的解决方案。