简体   繁体   中英

What is the difference between two different swapping function?

I would like to know the difference between 2 codes in performance. What are the advantages and disadvantages?

Code 1:

temp  = a;
a  = b;
b  = temp;

Code 2:

a = a + b;
b = a - b;
a = a - b;

The advantages of the first technique are that it is a universal idiom which is obvious and correct. It will work everywhere, on variables of any type. It is quite likely to be recognized by an optimizing compiler and replaced by an actual 'swap' instruction, if available. So besides being more clear and more correct, the first technique is likely to be more efficient, also.

The advantages of the second technique are that it avoids the use of a temporary variable, and that it is a deliciously obscure trick which is beloved by those who incessantly collect obscure tricks, and pose misguided "gotcha" interview questions involving obscure tricks, and (for all I know) who make their own programs less maintainable, less portable, and less reliable by cluttering them with obscure tricks.

The disadvantages of the first technique are: None .
(Theoretically, one might say there's a disadvantage in that it uses a temporary variable, but really, that's no disadvantage at all, because temporary variables are free. I don't think there's anyone on the planet who is still coding for a processor so limited in memory and registers that "saving" a temporary variable in this sort of way is something to actually worry about.)

The disadvantages of the second technique are that it is harder to write, harder for the reader to understand, and likely less efficient (perhaps significantly so). It "works" only on arithmetic types, not structures or other types. It won't work (it will quietly corrupt data) if it should happen be used in an attempt to swap data with itself. (More on this possibility later.) And if those aren't all bad enough, it is likely to be fundamentally buggy even under "ordinary" circumstances, since it could overflow, and with floating-point types it could alter one or both values slightly due to roundoff error, and with pointer types it's undefined if the pointers being swapped do not point within the same object.

You asked specifically about performance, so let's say a few more words about that. (Disclaimer: I am not an expert on microoptimization; I tend to think about instruction-level performance in rather abstract, handwavey terms.)

The first technique uses three assignments. The second technique uses an addition and two subtractions. On many machines an arithmetic operation takes the same number of cycles as a simple value assignment, so in many cases the performance of the two techniques will be identical. But it's hard to imagine how the second technique could ever be more efficient, while it's easy to imagine how the first technique could be more efficient. In particular, as I mentioned already, the first technique is easier for a compiler to recognize and turn into a more-efficient SWP instruction, if the target processor has one.


And now, some digressions. The second technique as presented here is a less-delicious variant of the traditional, deliciously obscure trick for swapping two variables without using a temporary. The traditional, deliciously obscure trick for swapping two variables without using a temporary is:

a ^= b;
b ^= a;
a ^= b;

Once upon a time it was fashionable in some circles to render these techniques in an even more deliciously obscure way:

a ^= b ^= a ^= b;       /* WRONG */
a += b -= a -= b;       /* WRONG */

But these renditions (while, yes, being absolutely exquisitely deliciously obscure if you like that sort of thing) have the additional crashing disadvantage that they represent undefined behavior , since they try to modify a multiple times in the same expression without an intervening sequence point. (See also the canonical SO question on that topic .)


In fairness, I have to mention that there is one actual circumstance under which the first technique's use of a temporary variable can be a significant disadvantage, and the second technique's lack of one can be therefore be an actual advantage. That one circumstance is if you are trying to write a generic 'swap' macro, along the lines of

#define Swap(a, b) (a = a + b, b = a - b, a = a - b)

The idea is that you can use this macro anywhere, and on variables of any type, and (since it's a macro, and therefore magic) you don't even have to use & on the arguments you call it with, as you would if it were a function. But in traditional C, at least, if you wanted to write a Swap macro like this, it was essentially impossible to do so using technique 1, because there was no way to declare the necessary temporary variable.

You weren't asking about this sub-problem, but since I brought it up, I have to say that the solution (although it is eternally frustrating to the lovers of delicious obscurity) is to just not attempt to write a "generic" macro to swap two values in the first place . You can't do it in C. (As a matter of fact, you could do it in C++, with the new definition of auto , and these days I guess C has some new way of writing generic macros, too.)

And there is actually an additional, crashing problem when you try to write a 'swap' macro this way, which is that it will not work — it will set one or both variables to 0 instead of swapping the values — if the caller ever tries to swap a value with itself. You might say that's not a problem, since maybe nobody would ever write Swap(x, x) , but in a less-than-perfectly-optimal sorting routine they might very easily write Swap(a[i], a[j]) where sometimes i happened to be equal to j , or Swap(*p, *q) where sometimes the pointer p happened to be equal to q .

See also the C FAQ List , questions 3.3b , 10.3 and 20.15c .

Always use the first one. The second one can introduce subtle bugs. If the variables are of type int and a+b is greater than INT_MAX then the addition will yield undefined behavior.

When it comes to performance, the difference is likely barely measurable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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