Skip to main content

Swap Two Numbers Intricate

ยท 8 min read
Linh Nguyen
T-90MS Main Battle Tank

The classic swapping two numbers. But there are more than it seems!

Look here, the classic CS 101 swapping two variables:

int tmp = a;
a = b;
b = tmp;

Yeah, this is the programming equivalent of wearing sensible shoes. It works, it's comfortable, and nobody's going to judge you for it. Your grandmother could read this code and nod approvingly while offering you cookies.

But what if I told you there are other ways? Ways that make your code look like you either failed math class spectacularly or discovered some forbidden programming knowledge that normal people aren't supposed to know about?

Method 1: The "I'm Too Cool for Temporary Variables" Approachโ€‹

First up, we have the arithmetic method for rebels who think extra variables are for weaklings:

a += b;  // No temp variable!
b = a - b; // This is fine...
a -= b; // ...right? RIGHT?

This works by turning your first variable into a mathematical hoarder -- it grabs both values, holds onto them like a dragon with treasure, then spits them back out in the right order through the magic of subtraction.

"But what about integer overflow?"

I hear you cry into the void.

Don't worry about it.

Seriously.

I've tested this thing with numbers so big they make your computer wheeze, and it still works. Java's two's complement arithmetic is like that friend who always has your back -- even when everything goes sideways, it somehow makes things work out in the end. It's math, but the kind of math that feels like cheating.

Source: trust me bro ๐Ÿ’€

Don't believe? Test it yourself.

Method 2: The Dark Arts (XOR Edition)โ€‹

Now, for those of you who want to write code that looks like you're summoning demons:

a ^= b;  // Confuse everyone, including yourself
b ^= a; // Confuse yourself more
a ^= b; // Somehow it works???

Welcome to the classic inverted square root magic hax, except this is actually more accurate!

This is the XOR swap, also known as "the thing that makes other programmers look at you like you just pulled a rabbit out of a hat, but they're not sure if it's impressive or concerning."

XOR has this weird property where if you XOR something with itself, you get zero. And if you XOR anything with zero, you get the original thing back. It's like the programming equivalent of "I know you are, but what am I?" but somehow more useful.

This method makes you feel like a bit-manipulation wizard. Your code reviews will be 50% people asking "how does this work?" and 50% people asking "why does this work?" It's the programming equivalent of showing up to a potluck with molecular gastronomy.

The Floating-Point Plot Twistโ€‹

Here's where things get spicy. Remember that arithmetic method? Well, it has trust issues with floating-point numbers.

double a = 0.1;
double b = 0.2;
// *does arithmetic swap*
// a is now 0.2
// b is now 0.10000000000000003

This happens because IEEE 754 (the floating-point standard) is basically that person who always rounds up the restaurant bill "for simplicity" but forgets to tell you. Most decimal numbers can't be represented exactly in binary, so you get these tiny errors that snowball faster than gossip in a small town.

And before you start throwing shade at Java, this isn't Java's fault -- it's a universal programmer headache. Python, C#, JavaScript, and pretty much every other language suffer from the same IEEE 754 shenanigans. Though honestly, no one would be surprised by JavaScript having number problems, considering it's the language that, with infinite wisdom, decided that 2 + "2" = "22" but 2 - "2" = 0. Because apparently addition and subtraction follow completely different rules in JavaScript land.

If you need precision with decimals, you'll want BigDecimal:

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
// But now you're back to using methods like add() and subtract()
// So much for being clever...

Using BigDecimal is like bringing a calculator to a mental math competition -- technically correct, but you've kind of missed the point of the whole exercise.

Now, technically, you could make the plus/minus method work with floating-point values if you do your research hard enough and dive deep into the IEEE 754 specification. But "eventually" making it work would cost you more time than it's worth, and you'd probably end up with a solution that's more fragile than a house of cards in a hurricane. Sometimes the juice just isn't worth the squeeze.

The XOR Reality Checkโ€‹

Oh, and that super cool XOR method? Yeah, it's got commitment issues. It absolutely refuses to work with floating-point numbers. Try it and Java will give you a compile error faster than you can say "but I thought I was being clever!"

double a = 3.14;
double b = 2.71;
a ^= b; // Compiler: "Nope. Not happening. Go sit in the corner."

XOR only works with integers because it's a bitwise operation, and floating-point numbers have this complex internal structure with sign bits, exponents, and mantissas. Trying to XOR them is like trying to use a screwdriver on a soup -- technically they're both things, but it's not going to end well.

"But what about a swap() method?" I hear you ask, probably while adjusting your imaginary monocle.

Nope. Don't even think about it. Java passes everything by value (even object references are passed by value), so a simple swap(a, b) method won't work. You'll end up swapping the copies inside the method while your original variables sit there unchanged, smugly judging your attempts at cleverness.

If you want that kind of functionality, you'll need to venture into other languages. C# lets you use the ref keyword to actually pass variables by reference, like a civilized language. Or you could embrace the dark side and use C/C++ with its pointer magic -- nothing says "I'm hardcore" like manually managing memory addresses and hoping you don't accidentally corrupt your entire program.

But in Java? You're stuck with the methods above. Java believes in protecting you from yourself, even if it means crushing your dreams of elegant swap functions.

The Ancient 32-bit Paranoia (Museum Edition)โ€‹

Oh, and here's a fun piece of programming archaeology for you: if you were swapping two long variables back in the dark ages of 32-bit systems, and you were somehow paranoid about "tearing" (a delightful concurrent programming nightmare), you might have reached for synchronized:

synchronized (someLockObject) {
long tmp = a;
a = b;
b = tmp;
}

"Tearing" happened because long values are 64 bits, but 32-bit systems could only handle them in two 32-bit chunks. So in a multithreaded environment, another thread might catch your long variable half-dressed -- seeing the first 32 bits from the old value and the last 32 bits from the new value. It was like walking in on someone changing clothes, but for numbers.

If you were truly desperate (and apparently enjoyed suffering), you could also reach for Java's ReentrantLock for more verbose, fine-tuned control. But seriously, are you that desperate? It's like using a chainsaw to cut your birthday cake -- technically possible, but everyone's going to question your life choices.

Thankfully, the good folks at the OpenJDK team had the wisdom to rightfully axe 32-bit support, probably while muttering "good riddance" under their breath. Nowadays, 64-bit systems are so trendy that 32-bit systems have joined punch cards and floppy disks in the computing museum.

So hopefully, you won't be dealing with this kind of ancient curse in modern times. But hey, now you know why some old-timers still get twitchy when they see non-synchronized long operations!

So When Should You Actually Use These?โ€‹

The honest answer?

Probably never.

Temporary variable method: This is your bread and butter. It's like a reliable friend who shows up when they say they will and doesn't try to impress you with magic tricks.

Arithmetic method: Use this when you want to show off in coding interviews or when you're working on embedded systems where every byte of memory costs more than your morning coffee.

XOR method: Perfect for when you want to write code that makes people go "wait, what?" Also great for competitive programming, where being unnecessarily clever is actually encouraged.

Look, I get it. These alternative methods are fun. They make you feel smart. They're conversation starters. But remember -- prefer simplicity to complexity. It is for your own sanity, and maybe for your team as well. You might feel smart, but your team wouldn't exactly be happy with the magic you have summoned.

Pro tip: Save the fancy stuff for toy projects and coding competitions. In real life, boring code that works is infinitely better than clever code that makes people cry.

Now go forth and swap responsibly! ๐ŸŽญ