使用无符号整数与有符号整数相比,是否存在性能收益或损失?
如果是这样,短整型和长整型也是如此吗?
使用无符号整数unsigned int
进行2的幂次方除法更快,因为可以优化成单个移位指令。使用有符号整数signed int
通常需要更多的机器指令,因为除法向零舍入,但右移则向下舍入。例如:
int foo(int x, unsigned y)
{
x /= 8;
y /= 8;
return x + y;
}
以下是相关的 x
部分(带符号除法):
movl 8(%ebp), %eax
leal 7(%eax), %edx
testl %eax, %eax
cmovs %edx, %eax
sarl $3, %eax
这里是相关的y
部分(无符号除法):
movl 12(%ebp), %edx
shrl $3, %edx
shrl
的第一个操作数应该是文字吗? - Manu343726在C++(以及C)中,有符号整数溢出是未定义的,而无符号整数溢出则被定义为循环。请注意,例如在gcc中,您可以使用-fwrapv标志使有符号溢出定义为循环(即包装)。
未定义的有符号整数溢出允许编译器假设不会发生溢出,这可能会引入优化机会。请参见例如此博客文章进行讨论。
INT_MAX + 1
是未定义行为,INT_MIN % -1
也是如此。发生了什么变化呢?现在对于任何非不确定值,signed_integer_type(any_integer_value)
都已被定义,并保证给出二进制补码结果。 - David Stoneunsigned
会比signed
具有相同或更好的性能。以下是一些例子:
signed
类型的数字,而gcc用1个指令,就像在unsigned
案例中一样)short
通常比int
具有相同或更差的性能(假设sizeof(short) < sizeof(int)
)。当你将算术运算的结果(通常是int
,而不是short
)分配给存储在处理器寄存器中的short
类型变量(也是int
类型)时,性能下降会发生。所有从short
到int
的转换都需要时间,很烦人。
注意: 一些DSP具有针对signed short
类型的快速乘法指令;在这种特定情况下,short
比int
更快。
至于int
和long
之间的区别,我只能猜测(我不熟悉64位体系结构)。当然,如果int
和long
大小相同(在32位平台上),它们的性能也相同。
几个人指出的一个非常重要的补充:
对于大多数应用程序,真正重要的是内存占用和使用带宽。您应该使用最小必需的整数(如short
,甚至signed/unsigned char
)来处理大型数组。
这将会提供更好的性能,但是收益是非线性的(即不是2或4的倍数),并且有些不可预测——它取决于您的应用程序中缓存大小以及计算和内存传输之间的关系。
short
的经验与你/任何其他人不同) - anatolyg这将取决于具体的实现方式。在大多数情况下,不会有任何区别。但如果您真的关心,您必须尝试所有您考虑的变体并测量性能。
无符号类型不仅在2的幂次方除法中更快,而且在除以其他任何值时也更快。如果您查看Agner Fog's Instruction tables,您会发现无符号除法与有符号版本具有类似或更好的性能
例如,在AMD K7上
指令 | 操作数 | 操作码 | 延迟周期 | 吞吐率倒数 |
---|---|---|---|---|
DIV | r8/m8 | 32 | 24 | 23 |
DIV | r16/m16 | 47 | 24 | 23 |
DIV | r32/m32 | 79 | 40 | 40 |
IDIV | r8 | 41 | 17 | 17 |
IDIV | r16 | 56 | 25 | 25 |
IDIV | r32 | 88 | 41 | 41 |
IDIV | m8 | 42 | 17 | 17 |
IDIV | m16 | 57 | 25 | 25 |
IDIV | m32 | 89 | 41 | 41 |
同样的事情适用于英特尔奔腾处理器
指令 | 操作数 | 时钟周期 |
---|---|---|
DIV | r8/m8 | 17 |
DIV | r16/m16 | 25 |
DIV | r32/m32 | 41 |
IDIV | r8/m8 | 22 |
IDIV | r16/m16 | 30 |
IDIV | r32/m32 | 46 |
当然,这些都是相当古老的。具有更多晶体管的新型架构可能会缩小差距,但基本的事情仍然适用:通常需要更多的微操作、更多的逻辑、更多的延迟才能进行带符号除法。
a[x]+=b
和 a[x]=b
区别开来,会使程序执行时间快了近2倍。而不,a[x]=b
并不是更快的那个。传统上,int
是目标硬件平台的本机整数格式。任何其他整数类型可能会导致性能损失。
编辑:
现代系统略有不同:
出于兼容性原因,在 64 位系统上,int
实际上可能是 32 位。我相信这在 Windows 系统上发生。
现代编译器在某些情况下隐式地使用 int
来执行较短类型的计算。
int
仍然是32位宽度,但64位类型(根据操作系统而定的long
或long long
)应该至少与其速度相当。 - Philippint
类型始终是32位宽度,无论处理器是否为64位。而long
类型是不同的:在Windows上是32位,在Linux和OS X上是一个字。 - Philippint
不一定始终为32位宽。 - mercury0114int
是CPU可以高效操作的类型。例如,在大多数64位平台上使用32位,因为它们都具有高效的32位整数操作,特别是x86-64,其中int
是本机整数格式,在机器代码中是默认的操作数大小。(完整的寄存器宽度为64位,但使用它需要每个指令额外的一个字节的机器代码)。通常int
也不会太大;很少是64位。但当然,在某些系统上实际上确实是这样,我记得一些旧的Cray计算机就是这样。 - Peter Cordes据我所知,在x86上,有符号/无符号不应该有任何区别。然而,短整型和长整型则是另一回事,因为对于长整型,需要移动到/从RAM的数据量更大(其他原因可能包括强制类型转换,如将短整型扩展为长整型)。