简体   繁体   English

C中的签名与未签名操作

[英]Signed vs Unsigned operations in C

Very simple question: 很简单的问题:

I have a program doing lots and lots of mathematical computations over ints and long longs. 我有一个程序在整数和长期内进行大量的数学计算。 To fit in an extra bit, I made the long longs unsigned, since I only dealt with positive numbers, and could now get a few more values. 为了适应额外的一点,我做了长长的无符号,因为我只处理正数,现在可以得到更多的值。

Oddly enough, this gave me a 15% performance boost, which I confirmed to be in simply making all the long long's unsigned. 奇怪的是,这给了我15%的性能提升,我确认只是简单地让所有长长的未签名。

Is this possible? 这可能吗? Are mathematical operations really faster with unsigned numbers? 使用无符号数字,数学运算真的更快吗? I remember reading that there would be no difference, and the compiler automatically picks out the fastest way to go whether signed or unsigned. 我记得读过没有区别,编译器会自动选择最快的方式,无论是签名还是未签名。 Is this 15% boost really from making the vars unsigned, or could it be something else affected in my code? 这个15%的提升真的是因为vars没有签名,还是可能是我的代码中的其他东西?

And, if it really is from making the vars unsigned, should I aim to make everything (even ints) unsigned, as I never need negative numbers, and every second is important if I can save it. 并且,如果它真的是使vars无符号,我应该瞄准使所有(甚至整数)无符号,因为我从不需要负数,如果我可以保存它,每一秒都很重要。

In some operations, signed integers are faster, in others, unsigned are faster: 在某些操作中,有符号整数更快,而在其他操作中,无符号整数更快:

  • In C, signed integer operations can be assumed not to wrap. 在C中,可以假定有符号整数运算不包装。 The compiler will take advantage of this in loop optimization, for example. 例如,编译器将在循环优化中利用这一点。 Comparisons can be optimized away similarly. 比较可以类似地进行优化。 (This can also lead to subtle bugs if you don't expect this). (如果您不期望这样,这也会导致细微的错误)。

  • On the other hand, unsigned integers do not have this assumption. 另一方面,无符号整数没有这个假设。 However, not having to deal with a sign is a big advantage for some operations, for example: division. 但是,不必处理符号对于某些操作来说是一个很大的优势,例如:除法。 Unsigned division by a constant power of two is a simple shift, but (depending on your rounding rules) there's a conditional off-by-1 for negative numbers. 通过2的常数幂进行的无符号除法是一个简单的移位,但是(取决于你的舍入规则)对于负数有一个有条件的除1。

Personally, I make a habit of only using unsigned integers unless I really, really do have a value which needs to be signed. 就个人而言,我习惯只使用无符号整数,除非我真的确实有一个需要签名的值。 It's not so much for performance as correctness. 性能与正确性无关。

You may see the effect magnified with long long, which (I'm guessing) is 64 bits in your case. 您可能会看到长效放大的效果,在我的情况下(我猜)是64位。 The CPU usually doesn't have single instructions do deal with these types (in 32 bit mode), so the slight added complexity for signed operations will be more noticeable. CPU通常没有单一指令来处理这些类型(在32位模式下),因此签名操作的轻微增加的复杂性将更加明显。

On a 32-bit processor, 64-bit integer operations are emulated; 在32位处理器上,模拟64位整数运算; using unsigned instead of signed means the emulation library doesn't have to do extra work to propagate carry bits etc. 使用unsigned而不是signed意味着仿真库不需要做额外的工作来传播进位等。

There are three cases where a compiler cares whether a variable is signed or unsigned: 在三种情况下,编译器会关心变量是有符号还是无符号:

  1. When the variable is converted to a longer type 当变量转换为更长的类型时
  2. When the comparison operators (greater-than, etc.) are applied 当应用比较运算符(大于等)时
  3. When overflows might occur 何时可能发生溢出

On some machines, conversion of signed variables to longer types requires extra code; 在某些机器上,将签名变量转换为更长的类型需要额外的代码; on other machines, a conversion may be performed as part of a 'load' or 'move' instruction. 在其他机器上,转换可以作为“加载”或“移动”指令的一部分来执行。

Some machines (mainly small embedded microcontrollers) require more instructions to perform a signed-versus-signed comparison than unsigned-versus-unsigned, but most machines have a full array of both signed and unsigned compare instructions available. 有些机器(主要是小型嵌入式微控制器)需要更多指令才能执行有符号与无符号无符号比较,但大多数机器都有完整的有符号和无符号比较指令。

When overflows occur with unsigned types, the compiler may have to add code to ensure that the defined behavior actually occurs. 当使用无符号类型发生溢出时,编译器可能必须添加代码以确保实际发生定义的行为。 No such code is required for signed types, because anything that might happen in the absence of such code would be permitted by the standard. 签名类型不需要这样的代码,因为标准允许在没有这些代码的情况下发生的任何事情。

The compiler doesn't pick if it's going to be unsigned or signed. 如果编译器未签名或签名,则编译器不会选择。 But, yes, in theory, unsigned with unsigned is faster than signed with signed . 但是,是的,理论上, unsigned with unsignedsigned with signed更快。 If you really want to slow things down, you'll go with signed with unsigned . 如果你真的想减慢速度,那么你将signed with unsigned And even worse: floats with integers . 更糟糕的是: floats with integers

It depends on the processor, of course. 当然,这取决于处理器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM