Potential Problem in "Swapping Values of Two Variables Without Using a Third Variable"

When would you swap two numbers without using a third variable?

At this point it's just a neat trick. Speed-wise if it makes sense though your compiler will recognize a normal swap and optimize it appropriately (but no guarantees that it will recognize weird xoring and optimize that appropriately).

Swapping two variable value without using third variable

Using the xor swap algorithm

void xorSwap (int* x, int* y) {
if (x != y) { //ensure that memory locations are different
*x ^= *y;
*y ^= *x;
*x ^= *y;
}
}



Why the test?

The test is to ensure that x and y have different memory locations (rather than different values). This is because (p xor p) = 0 and if both x and y share the same memory location, when one is set to 0, both are set to 0.
When both *x and *y are 0, all other xor operations on *x and *y will equal 0 (as they are the same), which means that the function will set both *x and *y set to 0.

If they have the same values but not the same memory location, everything works as expected

*x = 0011
*y = 0011
//Note, x and y do not share an address. x != y

*x = *x xor *y //*x = 0011 xor 0011
//So *x is 0000

*y = *x xor *y //*y = 0000 xor 0011
//So *y is 0011

*x = *x xor *y //*x = 0000 xor 0011
//So *x is 0011



Should this be used?

In general cases, no. The compiler will optimize away the temporary variable and given that swapping is a common procedure it should output the optimum machine code for your platform.

Take for example this quick test program written in C.

#include <stdlib.h>
#include <math.h>

#define USE_XOR

void xorSwap(int* x, int *y){
if ( x != y ){
*x ^= *y;
*y ^= *x;
*x ^= *y;
}
}

void tempSwap(int* x, int* y){
int t;
t = *y;
*y = *x;
*x = t;
}

int main(int argc, char* argv[]){
int x = 4;
int y = 5;
int z = pow(2,28);
while ( z-- ){
# ifdef USE_XOR
xorSwap(&x,&y);
# else
tempSwap(&x, &y);
# endif
}
return x + y;
}

Compiled using:

gcc -Os main.c -o swap

The xor version takes

real    0m2.068s
user 0m2.048s
sys 0m0.000s

Where as the version with the temporary variable takes:

real    0m0.543s
user 0m0.540s
sys 0m0.000s

Swapping the values of two variables without using third variable in C?

This algorithm does not work because it invokes undefined behavior on this line:

x=x+y-(y=x);
^ ^

You are modifying y and also using its value within the same sequence point as per section 6.5 of the draft C99 standard:

Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an
expression.72) Furthermore, the prior value shall be read only to
determine the value to be stored.73)

There is also the matter of unspecified behavior since the order of evaluation of the sub-expressions is unspecified:

The grouping of operators and operands is indicated by the syntax.74)
Except as specified later (for the function-call (), &&, ||, ?:, and
comma operators), the order of evaluation of subexpressions and the
order in which side effects take place are both unspecified.

In this case if you were using clang it would have provided the following warning:

warning: unsequenced modification and access to 'y' [-Wunsequenced]
x=x+y-(y=x);
~ ^

as far as I can tell by default. You can receive a similar warning from gcc by using -Wall.

There are several SO questions that cover how to swap without a temporary for example Swapping two variable value without using 3rd variable.

R: Swap two variables without using a third

For integers, you can use

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

and for strings, this would work

a <- "one"
b <- "two"
a <- paste(a,b, sep = "")
b <- substr(a,0,nchar(a) - nchar(b))
a <- substr(a,nchar(b) + 1, nchar(a))

> a
# two
> b
# one

Why Swapping without third variable not working here?

Your values of h and i are not quaranteed to be different.
Swapping in this case will not only not swap anything but also mess up your memory.

void selectsort(int*p ,int q){
int i,j,h,temp;
for(i=0;i<q-1;i++){
h=i; // <=== Here you start with identical values
for(j=i+1;j<q;j++){
if(p[h]>p[j]){
h=j; // This may or may not be executed.
}
}

// Here h can still be at same value as i.
// What happens in this case is shown in the comments below:
p[i]=p[i]+p[h]; // p[i]=p[i]+p[i]; ==> p[i] *=2;
p[h]=p[i]-p[h]; // p[i]=p[i]-p[i]; ==> p[i] = 0;
p[i]=p[i]-p[h]; // p[i]=p[i]-p[h]; ==> p[i] = 0;
}
}

You could add something like this before doing the swapping:

    if (i==h)
continue;

Note:

Apart from academic cases I would not suggest using such an approach.
Swapping without a temporary variable has lots of downsides:

  • Only works for integer types
  • Needs handling for overflow etc.
  • Needs handling for identical storage locations.
  • Needs extra arithmetic operations causing more code and longer execution time
  • Is confusing readers and harder to maintain

It also only has one advantage

  • Saves stack storage for 1 variable.

If your goal is to confuse readers, then you should search for a version using XOR instead of arithmetics. ;)

Swapping values of two variables without using a third one- Array

You can store them in an array (like you were trying to in some of the commented code), and then swap them one by one.

#include <stdio.h>
int main()
{
int x, y, p, i;
printf ("How many pairs?\n");
scanf ("%d", &p);
int a[p],b[p];
for(i=0; i<p; i++)
{
printf ("Enter values for pair %d:\n", i+1);
scanf("%d %d",&a[i],&b[i]);
}
for(i=0; i<p; i++)
{
x = a[i];
y=b[i];
x = x + y;
y = x - y;
x = x - y;
printf("Pair %d After Swapping: x = %d, y = %d\n", i+1, x, y);
}

return 0;
}

Try it here: http://goo.gl/5JJ7i3



Related Topics



Leave a reply



Submit