Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Re: Swapping two values

by integral (Hermit)
on Feb 15, 2003 at 08:28 UTC ( #235517=note: print w/replies, xml ) Need Help??

in reply to Swapping two values

In addition to the perl idiom of using a list assignment to swap values without a temporary variables, there is the idiom using the XOR operator. Although this does take three statements and doesn't fully take advantage of perl's list assignments, and so is more useful in other languages.

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

Update:Here's a contracted form of the above:

$a = $a ^ ($b = ($a ^= $b) ^ $b);

integral, resident of freenode's #perl

Replies are listed 'Best First'.
Re: Re: Swapping two values (Don't use XOR. Kill this meme.)
by sauoq (Abbot) on Feb 15, 2003 at 10:50 UTC

    As I've pointed out before, using XORs to swap values in perl will not work with references. (Note, by the way, that the OP was an inquiry about swapping references.)

    References aren't the only values this naive method will break on. Try it with $a = 1; $b = "0foo"; for instance.

    In C or assembly, you can swap values with bitwise XOR to avoid the use of temporary storage. It's rarely necessary, but comes in handy when you need things to be real fast and you have a limited number of registers. In such lower level languages, it works on strings because strings are pointers and pointers are ints and XOR works nicely on ints. In perl, however, the XOR method will do a bitwise XOR on the whole string. When all you want to do is swap values, that's grossly inefficient.

    Bitwise XOR should never be used to swap values in perl. It isn't maintainable. It isn't efficient. It isn't clever. Don't do it.

    "My two cents aren't worth a dime.";
Re: Re: Swapping two values
by Anonymous Monk on Feb 15, 2003 at 16:43 UTC
    While clever, it is wrong even in other languages if there is any possibility that $a and $b are the same (or overlap).

      In languages like C (and not Perl) where it sometimes makes sense to use this method for swapping values, it will work just fine even if the values are the same. I'm unsure what you mean by "overlap." To see that it will work, try it with all four combinations of 2 bits:

      A | B | A = A^B | B = A^B | A = A^B | A | B ===|===|=========|=========|=========|===|=== 0 | 0 | 0 = 0^0 | 0 = 0^0 | 0 = 0^0 | 0 | 0 ---+---+---------+---------+---------+---+--- 0 | 1 | 1 = 0^1 | 0 = 1^1 | 1 = 1^0 | 1 | 0 ---+---+---------+---------+---------+---+--- 1 | 0 | 1 = 1^0 | 1 = 1^0 | 0 = 1^1 | 0 | 1 ---+---+---------+---------+---------+---+--- 1 | 1 | 0 = 1^1 | 1 = 0^1 | 1 = 0^1 | 1 | 1
      See? It works fine even when the values are equal.

      But, don't do it in perl!

      "My two cents aren't worth a dime.";

        I think that the point the Anonymous Monk was making that it falls over badly if $a and $b refer to the same sequence of bits in memory. Consider:

        # swap ($s, $p1, $p2, $n); # in $s swap the $n bits at bit $p1 and $p2 sub swap { vec($_[0],$_[1],$_[3]) ^= vec($_[0],$_[2],$_[3]); vec($_[0],$_[2],$_[3]) = vec($_[0],$_[1],$_[3]) ^ vec($_[0],$_[2], +$_[3]); vec($_[0],$_[1],$_[3]) = vec($_[0],$_[1],$_[3]) ^ vec($_[0],$_[2], +$_[3]); }; # swap first two and second two chars my $string = "ABCD"; print "$string\n"; swap($string, 0,16,16); print "$string\n";

        The problem with code like this is that it falls down badly if the bits sequences being swapped overlap. Consider:

        # swap first character with itself swap($string, 0, 0, 8);

        Anything XORed with itself is zero. Oops :-)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://235517]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2017-03-30 01:25 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (353 votes). Check out past polls.