swap two integers without using a tmp variable?

H

Howard

Julie said:
Small footprint embedded systems would be a good place/reason.

You don't have room for one integer? (Then you also don't have room for the
code to guard aginst swapping a number with itself, do you?) Anyone out
there ACTUALLY had to write a program where there wasn't room for a single
temporary integer value??? I seriously doubt it. (And don't embedded
systems ever use registers for this? That's what I usually use when I write
in assembler, since it's faster than using RAM.)

-Howard
 
J

Julie

Howard said:
You don't have room for one integer? (Then you also don't have room for the
code to guard aginst swapping a number with itself, do you?) Anyone out
there ACTUALLY had to write a program where there wasn't room for a single
temporary integer value??? I seriously doubt it. (And don't embedded
systems ever use registers for this? That's what I usually use when I write
in assembler, since it's faster than using RAM.)

-Howard

Talk to Ed Nisley -- he regularly talks about bit counting in embedded systems
in his "Embedded Space" forum in DDJ.

Guarding against self-swapping could be an (assumed) precondition and not
included in the code.

Just trying to think outside of the box here, and not limiting it to a 'there
is no good reason to do it' mentality.
 
W

Walter Tross

(e-mail address removed) 2004-06-22 :
Well... You *could* add a self-assignment guard.

Sometimes coders find themselves working on extremely limited hardware.
Like a smoke detector or something. And every variable is taking up
the very limited RAM that was only allowed by having an arm-wrestling
match with the comptroller and the accountant.

It seems like nobody is taking in account the fact that the temporary
variable of a simple swap will most likely be a register, and this is very
likely to be true also when swapping classes member by member.

Walter Tross
 
R

Roman Ziak

Walter Tross said:
It seems like nobody is taking in account the fact that the temporary
variable of a simple swap will most likely be a register, and this is very
likely to be true also when swapping classes member by member.

Walter Tross

This is true. However I can imagine the situation when you do not have that
register, because the remaining registers hold other importand data :)
Fortunately, some micros implement swapping in single instruction (similarly
to x86's XCHG).

Roman
 
B

Brandon

You don't have room for one integer? (Then you also don't have room for
Guarding against self-swapping could be an (assumed) precondition and not
included in the code.

Unless the swap function was being used in some odd situation where
there was no possibility of the two variables having the same value,
you would end up doing the comparison yourself prior to the function
call anyway (or at least you SHOULD, in which case you would have to
have room for the temporary integer.) As *unlikely* as it may be that
the parameters wouldn't have the same values, unless it is
*impossible* (assuming there are no bugs elsewhere in your program of
course,) it would bad programming etiquette to do the swap without the
comparison. It sounds to me like this question is nothing more than
programming trivia anyway.

-Brandon
 
R

Risto Lankinen

1) Well... You *could* add a self-assignment guard.

2) Sometimes coders find themselves working on extremely limited hardware.

Aren't 1) and 2) mutually exclusive, especially when the
alternative (of using a temp) is typically going to be smaller
than 1) in size anyway?!?

- Risto -
 
B

Bill Seurer

Howard said:
You don't have room for one integer? (Then you also don't have room for the
code to guard aginst swapping a number with itself, do you?) Anyone out
there ACTUALLY had to write a program where there wasn't room for a single
temporary integer value???

Yes. During system startup there may not be ANY local/stack storage
available because you haven't gotten far enough along for such things to
exist yet.

I've also listened to people who worked on hardware that didn't have
local storage whine about "arrogrant compiler writers".
 
N

Niklas Borson

Julie said:
Talk to Ed Nisley -- he regularly talks about bit counting in embedded systems
in his "Embedded Space" forum in DDJ.

Are you sure there's even a difference in storage requirements?
Low-level optimizations like this are usually best left to the
compiler.

Here are two inline swap functions: swap1 which uses a temporary,
and swap2 which uses the XOR trick.

inline void swap1(int& a, int &b)
{
int temp = a;
a = b;
b = temp;
}

inline void swap2(int& a, int &b)
{
b = a ^ b;
a = b ^ a;
b = a ^ b;
}

For comparison, let's define a couple of test functions which
use swap1 and swap2, respectively, but are otherwise identical.
The conditional is there to ensure that swap can't be optimized
away entirely.

int Test1(int a, int b)
{
if (a > b) swap1(a, b);
return (a + 1) * b;
}

int Test2(int a, int b)
{
if (a > b) swap2(a, b);
return (a + 1) * b;
}

Here is the x86 assembly language output my compiler produces
for these two functions:

?Test1@@YAHHH@Z PROC NEAR
; Line 17
mov eax, DWORD PTR _a$[esp-4]
mov ecx, DWORD PTR _b$[esp-4]
cmp eax, ecx
jle SHORT Test$1
mov edx, eax
mov eax, ecx
mov ecx, edx
Test$1:
; Line 18
add eax, 1
imul eax, ecx
; Line 19
ret 0
?Test1@@YAHHH@Z ENDP

?Test2@@YAHHH@Z PROC NEAR
; Line 23
mov eax, DWORD PTR _a$[esp-4]
mov ecx, DWORD PTR _b$[esp-4]
cmp eax, ecx
jle SHORT Test1$1
xor ecx, eax
xor eax, ecx
xor ecx, eax
Test1$1:
; Line 24
add eax, 1
imul eax, ecx
; Line 25
ret 0
?Test2@@YAHHH@Z ENDP

They are identical except that the first uses three register MOV
and the second three register XOR instructions to do the swap.
Neither uses any memory, although the first uses an additional
register (which is already available).

Now let's consider another variation in which we remove the
condition:

int Trivial1(int a, int b)
{
swap1(a, b);
return (a + 1) * b;
}

int Trivial2(int a, int b)
{
swap2(a, b);
return (a + 1) * b;
}

And here's the assembly output:

?Trivial1@@YAHHH@Z PROC NEAR
; Line 30
mov eax, DWORD PTR _b$[esp-4]
add eax, 1
imul eax, DWORD PTR _a$[esp-4]
; Line 31
ret 0

?Trivial2@@YAHHH@Z PROC NEAR
; Line 35
mov ecx, DWORD PTR _a$[esp-4]
mov edx, DWORD PTR _b$[esp-4]
xor edx, ecx
xor ecx, edx
mov eax, ecx
xor eax, edx
; Line 36
add ecx, 1
imul eax, ecx
; Line 37
ret 0
?Trivial2@@YAHHH@Z ENDP

What's going on here? Well, in the first case, the compiler
was able to optimize away the swap entirely and just do the
equivalent of return (b + 1) * a.

In the second case, the use of the XOR trick obscured the
intent of the code so the compiler just had to follow the
instructions literally. This is a common problem with using
tricky, low-level optimizations in source code. Compilers
can optimize better using the "as-if" rule if the effect of
the code is straightforward.
Guarding against self-swapping could be an (assumed)
precondition and not included in the code.

This places a burden on the user of the function to understand
the restruction and perform the test his/herself if necessary.
It is an error waiting to happen.
Just trying to think outside of the box here, and not limiting
it to a 'there is no good reason to do it' mentality.

There's a natural tendency to be seduced by clever tricks that
seem to promise a tiny gain in efficiency. Given that, it seems
to me that "thinking outside the box" involves taking into
account other factors that may not be so obvious. Let's weigh
the pros and cons in this case, shall we?

Pros:
* May save one int of memory in rare cases (i.e., where
there are no available registers)

Cons:
* Obfuscates the source code.
* Is less general (e.g., doesn't work for UDTs).
* Intruduces potential obscure bugs due to self-swap.
* Undermines compiler optimizations.

It seems to me that in this case there really is no good
reason to do it. That's not a "mentality" but a considered
judgment.
 
H

Howard

Bill Seurer said:
Yes. During system startup there may not be ANY local/stack storage
available because you haven't gotten far enough along for such things to
exist yet.

I've also listened to people who worked on hardware that didn't have
local storage whine about "arrogrant compiler writers".


If there's no local/stack storage, then what exactly would you perform the
swap on? The assumption was that we were trying to swap two integers
without using a third as a temporary. Where do the two integers being
swapped exist? I'm questioning when you might have a case where you have
two such integers needing to be swapped, but don't have room for that one
temporary integer (even in a register).

I'm also curious (now) as to what kind of assembly language doesn't allow
you to define any local data. Can't you define the data in the code? How
the heck are you supposed to accomplish anything in code if you can't have
any variables to work with? And what do you mean by "you haven't gotten far
enough along for such things to exist yet"? Is there some sequence of
operations in your hardware that allows code to execute without any data
until something happens that magically allows you to use data?

-Howard
 
J

JKop

Maxim Yegorushkin posted:
I tried doing so and it produced the expected result.

What was supposed to happen?

Try this

unsigned int a = 2147483651;

unsigned int b = 3250783651;

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


That's why you use a temp variable!


-JKop
 
B

Bill Seurer

Howard said:
If there's no local/stack storage, then what exactly would you perform the
swap on?

Static storage.
The assumption was that we were trying to swap two integers
without using a third as a temporary. Where do the two integers being
swapped exist? I'm questioning when you might have a case where you have
two such integers needing to be swapped, but don't have room for that one
temporary integer (even in a register).

It's doubtful this particular case would come up. i was answering the
more general question about there being programs without "room" for
local variables.
I'm also curious (now) as to what kind of assembly language doesn't allow
you to define any local data. Can't you define the data in the code? How
the heck are you supposed to accomplish anything in code if you can't have
any variables to work with? And what do you mean by "you haven't gotten far
enough along for such things to exist yet"? Is there some sequence of
operations in your hardware that allows code to execute without any data
until something happens that magically allows you to use data?

At certain points as some hardware starts there isn't any stack space
from which to allocate. Honest. Think really-low-level BIOS if all you
are familiar with is PCs.
 
N

Niklas Borson

Bill Seurer said:
Yes. During system startup there may not be ANY local/stack storage
available because you haven't gotten far enough along for such things to
exist yet.

Please explain how it is possible for *any* C or C++ code to execute
under these circumstances. (Remember, everything is a function...)
Surely such startup code would be written in assembler.
I've also listened to people who worked on hardware that didn't have
local storage whine about "arrogrant compiler writers".

I wouldn't know, not having done this kind of programming, but it
seems reasonable that compiler writers would have to make (and document)
certain basic assumptions about the target execution environment.

When you say "no local storage," do you actually mean no RAM, only
registers? If so, that sounds like a pretty special circumstance where
one should expect to use assembly language.
 
B

Bill Seurer

Niklas said:
I wouldn't know, not having done this kind of programming, but it
seems reasonable that compiler writers would have to make (and document)
certain basic assumptions about the target execution environment.

When you say "no local storage," do you actually mean no RAM, only
registers? If so, that sounds like a pretty special circumstance where
one should expect to use assembly language.

The specific case I am thinking of was a guy who worked with a group
that didn't use a "high level language" but wanted to. He was griping
about how all the compilers made assumptions without asking "potential"
users what they need. I don't think he ever got what he wanted but he
sure was upset about it.
 
J

Julie

Niklas Borson wrote:
It seems to me that in this case there really is no good
reason to do it. That's not a "mentality" but a considered
judgment.

In your case, and *only* your case.

Re-read the thread, there are several responses which more or less state 'there
is no good reason to do it' -- which is an inappropriate blanket statment and
definitely inside the box mentality.

Use what is appropriate for a given situation (hardware, target, compiler,
etc.) -- period. If that means the xor trick, then use it, if not, then use
something else like std::swap or whatever is necessary _and_appropriate_.

With the exception of the blanket 'don't do it' statements, this thread has
been enlightening and informative.
 
S

Steve

The question on how to do the swapping without tmp variable was just
part of a question in a interview test that I went through.I,m not
trying to save/conserve any space or memory or doing anything funny,
anyway there is already a std::swap template available in c++.....
 
M

Maxim Yegorushkin

JKop said:
Try this

unsigned int a = 2147483651;

unsigned int b = 3250783651;

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

On what platform? On x86 it works fine.
 
M

Maxim Yegorushkin

Pete said:
On most architectures it works just fine. On those architectures, "try
it" gives the wrong answer.

I'd like to know about architectures where that code does not work. I'm curious if there are processors where addition/substruction processor command does not wrap result using modulo.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top