[comp.lang.c] swap

cik@l.cc.purdue.edu (Herman Rubin) (01/20/88)

If the hardware does not have a swap instruction, the following (which I
believe is easier to read than what was originally posted) is likely to be
as fast as any other way to exchange two entities of the same size, assuming
that the exclusive or equal operation is in hardware, and that the operation
does not introduce access conflicts:

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

I have used it on various machines.  Of course, a particular implementation
of C might not let you use it on pointers or floats; this is a defect in C,
as there is no way the hardware can give the wrong answer(s).
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (ARPA or UUCP) or hrubin@purccvm.bitnet

chip@ateng.UUCP (Chip Salzenberg) (01/23/88)

In article <661@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>
>	a ^= b;
>	b ^= a;
>	a ^= b;
>
>I have used it on various machines.  Of course, a particular implementation
>of C might not let you use it on pointers or floats; this is a defect in C,
>as there is no way the hardware can give the wrong answer(s).

Sorry, but this is not a "defect in C".  This is a reflection of the fact
that pointers and floats may not (portably) be treated as arbitrary bit
strings.

For example: the '286 and '386, in protected mode, require that any value
loaded into a segment register be a valid segment selector.  Therefore:

	 if   a and b are "far" (segment+offset) pointers,
	and   (a ^ b) is an invalid pointer (probable),
	and   a is a register variable (possible),
       then   "a ^= b", if it compiled at all, will cause a trap.

Please repeat after me:

               "Pointers are not just integers in disguise."

-- 
Chip Salzenberg                 UUCP: "{codas,uunet}!ateng!chip"
A T Engineering                 My employer's opinions are a trade secret.
       "Anything that works is better than anything that doesn't."

tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) (08/22/89)

       To swap two variables x,y in C without using a temporary variable:

       /* begin swap */
       x += y;
       y = x - y;
       x -= y;
       /* end swap */

       Just curious...(this looks pretty valid) does anyone know an even
simpler method?  I would never program this way -- it's more of a theory
question.  I've been told that it can't be done (???).
Tim Gottschalk
Pgh, PA

tromp@piring.cwi.nl (John Tromp) (08/22/89)

tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:


>       To swap two variables x,y in C without using a temporary variable:

>       /* begin swap */
>       x += y;
>       y = x - y;
>       x -= y;
>       /* end swap */

>       Just curious...(this looks pretty valid) does anyone know an even
>simpler method?  I would never program this way -- it's more of a theory
>question.  I've been told that it can't be done (???).
>Tim Gottschalk
>Pgh, PA

How about

x^=y^=x^=y;

Avoids possible overflow problems and looks great in an
Obfuscated C Code entry too!

John Tromp (tromp@cwi.nl)

generous@dgis.daitc.mil (Curtis Generous) (08/22/89)

tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>       To swap two variables x,y in C without using a temporary variable:
>       /* begin swap */
>       x += y;
>       y = x - y;
>       x -= y;
>       /* end swap */
>       Just curious...(this looks pretty valid) does anyone know an even
>simpler method?  I would never program this way -- it's more of a theory
>question.  I've been told that it can't be done (???).
>Tim Gottschalk
>Pgh, PA

Saw this come across the net a few months back.  Don't know where it came
from.

	swap( a , b )
	    unsigned *a, *b;
	{
	    *a ^= *b ;
	    *b ^= *a ;
	    *a ^= *b ;
	}

I'm not sure it is any simpler, just another original approach.

--curtis
-- 
Curtis C. Generous
DTIC Special Projects Office (DTIC-SPO)
ARPA: generous@daitc.mil
UUCP: {uunet,vrdxhq}!dgis!generous

cik@l.cc.purdue.edu (Herman Rubin) (08/22/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
> 
>        To swap two variables x,y in C without using a temporary variable:
> 
>        /* begin swap */
>        x += y;
>        y = x - y;
>        x -= y;
>        /* end swap */
> 
>        Just curious...(this looks pretty valid) does anyone know an even
> simpler method?  I would never program this way -- it's more of a theory
> question.  I've been told that it can't be done (???).
> Tim Gottschalk
> Pgh, PA

As a function call, it is not worth while.  But for switching registers in
a tights situation on a machine without instruction overlap, it is likely to
be as fast as anything.  One needs three instructions, and since the operations
may be as fast as moves, no time is lost, compared to

        /* begin swap */
        temp = y;
        y = x;
        x = temp;
        /* end swap */

except that if x and y are the same, the second will work but not the first.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

chris@mimsy.UUCP (Chris Torek) (08/22/89)

Before anyone charges off to `correct' Herman Rubin....  (Note: I have
compressed these vertically and elided some text.)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu> tg1e+@andrew.cmu.edu
(Timothy R. Gottschalk) writes:
>>To swap two variables x,y in C without using a temporary variable:
>>	x += y; y = x - y; x -= y;

In article <1524@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>... for switching registers in a tights situation on a machine without
>instruction overlap, it is likely to be as fast as anything.  One needs
>three instructions, and since the operations may be as fast as moves,
>no time is lost, compared to
>
>	temp = y; y = x; x = temp;
>
>except that if x and y are the same, the second will work but not the first.

Again, before you `correct' this: that is, not that x and y have the
same *value*, but rather that x and y name the same storage location:

	int a = 1, *x = &a, *y = &b;
	*x += *y; *y = *x - *y; *x -= *y;

which winds up setting `a' to 0, rather than swapping it with itself.

The xor-trick is more often seen in the `swap registers in a tight
situation' situation than the add/subtract trick (it has the advantage
of working on two-address machines, as well).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

maart@cs.vu.nl (Maarten Litmaath) (08/22/89)

tromp@piring.cwi.nl (John Tromp) writes:
\...
\x^=y^=x^=y;

Evaluation order undefined.  Although it works on most compilers (notable
exception: Amsterdam Compiler Kit acc), the compiler is free to rearrange
the expression as follows:

	tmp = x;
	x ^= y;
	y ^= x;
	x = tmp ^ y;

ACK lint(1) will catch this one.  NONE of the other lint(1)s I've tried did
(BSD, SunOS, SysV).
I discovered this lint bug when trying to compile the following program with
acc (my 1988 Obfuscated C Code Contest winning entry):

main(argc, argv)
int	argc;
char	**argv;
{
	while (*argv != argv[1] && (*argv = argv[1]) && (argc = 0) || (*++argv
		&& (**argv && ((++argc)[*argv] && (**argv <= argc[*argv] ||
		(**argv += argc[*argv] -= **argv = argc[*argv] - **argv)) &&
		--argv || putchar(**argv) && ++*argv--) || putchar(10))))
		;
}

Line 7 should be changed to:

	(**argv ^= argc[*argv] ^= **argv) && (argc[*argv] ^= **argv)) &&

BTW, there's another non-portability:

	putchar(10)

which assumes ASCII.
-- 
"rot H - dD/dt = J, div D = rho, div B = 0, |Maarten Litmaath @ VU Amsterdam:
  rot E + dB/dt = 0" and there was light.   |maart@cs.vu.nl, mcvax!botter!maart

roelof@idca.tds.PHILIPS.nl (R. Vuurboom) (08/23/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu> tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>
>       To swap two variables x,y in C without using a temporary variable:
>
>       /* begin swap */
>       x += y;
>       y = x - y;
>       x -= y;
>       /* end swap */
>
>       Just curious...(this looks pretty valid) does anyone know an even
>simpler method?  I would never program this way -- it's more of a theory
>question.  I've been told that it can't be done (???).
						   ^^^
						   hey ma, thars one o dem
						   trigraphs again...:-)

This algorithm caught me out once. Try the following:

#define swap(x,y)  { x += y; \
		     y = x-y; \
		     x -= y; }

main()
{
	int i = 3;
	int j = 4;

	swap(i,j);
	printf ("i = %d  j = %d\n",i,j);

	i = 3;

	swap(i,i);
	printf ("i = %d\n",i);
}

-- 
I don't know what the question means, but the answer is yes...
KLM - Koninklijke Luchtvaart Maatschappij => coneenclicker lughtfart matscarpie
Roelof Vuurboom  SSP/V3   Philips TDS Apeldoorn, The Netherlands   +31 55 432226
domain: roelof@idca.tds.philips.nl             uucp:  ...!mcvax!philapd!roelof

jsb@advdev.LBP.HARRIS.COM (FLEA) (08/23/89)

In article <8350@boring.cwi.nl> tromp@piring.cwi.nl (John Tromp) writes:
:		 (Timothy R. Gottschalk) writes:
:
:>       To swap two variables x,y in C without using a temporary variable:
:
:>       /* begin swap */
:>       x += y;
:>       y = x - y;
:>       x -= y;
:>       /* end swap */
:
:>       Just curious...(this looks pretty valid) does anyone know an even
:
:How about
:
:x^=y^=x^=y;
:
:Avoids possible overflow problems and looks great in an
:Obfuscated C Code entry too!

Sorry, folks, both of these are illegal if x and y are pointers.

davej@mrsvr.UUCP (David Johnson x4-6506) (08/23/89)

From article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, by tg1e+@andrew.cmu.edu (Timothy R. Gottschalk):
= 
=        To swap two variables x,y in C without using a temporary variable:
= 
=        /* begin swap */
=        x += y;
=        y = x - y;
=        x -= y;
=        /* end swap */
= 
=        Just curious...(this looks pretty valid) does anyone know an even
= simpler method?  I would never program this way -- it's more of a theory
= question.  I've been told that it can't be done (???).
= Tim Gottschalk
= Pgh, PA

This code should work fine for numeric x,y that aren't TOO large (so that
the first line does not cause overflow - though even that may work (depending
on your particular compiler)) or for float x,y that are not excessively
far apart in precision.  If you set x = 1.0e+09 and y = 1.0e-8, the swap code
above results in x = 0 and y = 1.0e+09.  Also, low-order bits could be
lost due to rounding/truncation of float's.

A more intriguing (and less obvious) way is to do:
  /* begin swap */
  x ^= y;
  y ^= x;
  x ^= y;
  /* end swap */

Alas, in C, the bitwise OR only works with int's and char's :-(.               
Of course, you can type-cast, but it doesn't look as neat.  

Dave Johnson - Computer People Unlimited @ GE Medical Systems.

dfp@cbnewsl.ATT.COM (david.f.prosser) (08/23/89)

In article <8350@boring.cwi.nl> tromp@piring.cwi.nl (John Tromp) writes:
>How about
>
>x^=y^=x^=y;
>
>Avoids possible overflow problems and looks great in an
>Obfuscated C Code entry too!

This code need not do what was intended.  In particular, it requires that
"x" be assigned the result of the right-most ^= operation prior to its
value being used in the left-most ^= operation.  To eliminate this
evaluation-order dependent behavior, some form of sequence point must be
used between these two operations.  For example

	y^=x^=y,x^=y;

See section 3.3, and in particular footnote 31 (page 39) of the pANS.

Dave Prosser	...not an official X3J11 answer...

cpcahil@virtech.UUCP (Conor P. Cahill) (08/23/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>        To swap two variables x,y in C without using a temporary variable:
>        x += y;
>        y = x - y;
>        x -= y;

The problem with this method is that it will be easy to overflow the
variables in the first statement.   For example if x and y are short (16 bit)
integers and x contains 18,000 and y contains 19,000 the x will overflow to 
negative territory on the first assignment and throw off the rest of the 
equations.  If x & y are large enough the overflow could just be lost.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9240	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

platt@ndla.UUCP (Daniel E. Platt) (08/23/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
> 
>        To swap two variables x,y in C without using a temporary variable:
> 
>        /* begin swap */
>        x += y;
>        y = x - y;
>        x -= y;
>        /* end swap */
> 
>        Just curious...(this looks pretty valid) does anyone know an even
> simpler method?  I would never program this way -- it's more of a theory
> question.  I've been told that it can't be done (???).
> Tim Gottschalk
> Pgh, PA


One way that works with bit patterns is:

x ^= y;
y ^= x;
x ^= y;

(If I'm not mistaken, ^ is exclusive or.  If not, that's what I mean
in the above expression.)

For a proof:

x ^ (x ^ y) = (x ^ x) ^ y = 0 ^ y = y.
y ^ (x ^ y) = x ^ (y ^ y) = x ^ 0 = x.

Then,

x ^= y;  /* x now contains x ^ y */
y ^= x;  /* y now contains y ^ (x ^ y) = x */
x ^= y;  /* x now contains x ^ (x ^ y) = y */

Is this what you had in mind?

By the way, this is a trick commonly used in processing bitmapped
graphics -- such as in X11 or Macintosh stuff.

Dan Platt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
||                                     1(914)945-1173            ||
||        Dan Platt                    1(914)941-2474   		 ||
||        Watson (IBM)                 PLATT@YKTVMV.BITNET       ||
||                           ..!uunet!bywater!scifi!ndla!platt   ||
||                                                               ||
||     The opinions expressed here do not necessarily reflect    ||
||                   those of my employer!                       ||
||                                                               ||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/23/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu> tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>       x += y;
>       y = x - y;
>       x -= y;

This is an old trick (usually done using XOR instead of + and -).  Your
version can fail if arithmetic overflow occurs.

karzes@mfci.UUCP (Tom Karzes) (08/23/89)

In article <40@dgis.daitc.mil> generous@dgis.daitc.mil (Curtis Generous) writes:
>tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>>       To swap two variables x,y in C without using a temporary variable:

Here are some ways to do it:

    1.  x += y      y = x - y   x -= y
    2.  x -= y      y += x      x = y - x
    3.  x = y - x   y -= x      x += y
    4.  x ^= y      y ^= x      x ^= y

In each case, the operation used is such that given the value of x op y,
along with either x or y, one can recover the original value of the other
variable.

This reminds me of an old space saving trick for doubly linked lists.  One
can create a linked list which may be traversed in either direction using
a single pointer field.  In that field, store the xor (or the sum, or the
difference) of the predecessor and successor addresses.  (I know this isn't
legal C, so don't bother flaming.  The point is that it works on normal
computer hardware.)  All you have to do to traverse the list in a given
direction is keep the value of the previous node around and xor it with
the pointer field in the current node.  In fact, the code which does this
doesn't even have to know the direction in which it's going.  You just
have to keep pointers to the first and last elements, and seed the walk
at either end with a zero previous pointer.  The catch is that this
method only works for walking the list from the head or the tail.  You
can't start in the middle because you don't have any adjacent address
to get you started.  For example, you can't delete an element from the
list if all you have is its address; some additional context is needed.

pmontgom@sonia.math.ucla.edu (Peter Montgomery) (08/23/89)

In article <19211@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>The xor-trick is more often seen in the `swap registers in a tight
>situation' situation than the add/subtract trick (it has the advantage
>of working on two-address machines, as well).

	Furthermore, the xor trick also preserves +0 and -0 on 
one's complement machines, while the add/subtract trick does not.

	Swapping is really just another instance of the recently 
discussed problem of functions returning multiple values 
(e.g., quotient/remainder, cosine/sine, function value/derivative, 
maximum/minimum, less than flag/equality flag/greater than flag,
upper bound/lower bound, sign/exponent/mantissa, 
character read/EOF flag/error indicator):  modern languages should
allow the user to write something like

	(x, y) := (y, x);

Here "(y,x)" denotes "the two expressions y and x" while
"(x,y)" denotes "the two variables (or array elements, or lvalues) x and y".
The language semantics should stipulate that all expressions on the
right side and all addresses (or register locations) 
of variables on the left side will be determined first (order 
determined by the compiler), and then the assignments will be made 
(again in a compiler-determined order).  A consequence is that 
variables on the left side may not be aliased to each other unless 
(as here) the corresponding right sides will necessarily be equal. 
--------
        Peter Montgomery
        pmontgom@MATH.UCLA.EDU 

maart@cs.vu.nl (Maarten Litmaath) (08/23/89)

jsb@advdev.LBP.HARRIS.COM (FLEA) writes:
\In article <8350@boring.cwi.nl> tromp@piring.cwi.nl (John Tromp) writes:
\:		 (Timothy R. Gottschalk) writes:
\...
\:>       x += y;
\:>       y = x - y;
\:>       x -= y;
\...
\:x^=y^=x^=y;
\...
\Sorry, folks, both of these are illegal if x and y are pointers.

Or if they're structs! :-)
-- 
"rot H - dD/dt = J, div D = rho, div B = 0, |Maarten Litmaath @ VU Amsterdam:
  rot E + dB/dt = 0" and there was light.   |maart@cs.vu.nl, mcvax!botter!maart

pmaniac@walt.cc.utexas.edu (Noah Friedman) (08/23/89)

In article <1061@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>>        To swap two variables x,y in C without using a temporary variable:
>>        x += y;
>>        y = x - y;
>>        x -= y;
>
>The problem with this method is that it will be easy to overflow the
>variables in the first statement.   For example if x and y are short (16 bit)
>integers and x contains 18,000 and y contains 19,000 the x will overflow to 
>negative territory on the first assignment and throw off the rest of the 
>equations.  If x & y are large enough the overflow could just be lost.

To prevent this problem, why not cast the arguments as doubles?

void swap(double *x, double *y) 
{
    *x += *y;
    *y = *x - *y;
    *x -= *y;
}

func()
{
 int a, b;

    ...
    swap((double *) &a, (double *) &b);
    ...
}

This function should then work with any type, providing you type cast.
Of course, there is the possibility of loss of precision, but this
only applies to floating point variables.

Personally I'd write the swap function the traditional way, using 3
variables. And if I had a C++ compiler I'd overload swap() to handle
any type.

-=*=-----
pmaniac@walt.cc.utexas.edu (Noah Friedman)

Any opinions expressed in this article are entirely my own and are not
necessarily those of any official organization, including UT Austin.

for (eat=food; food != food_val(DOG); eat++, food--) ;
-=*=-----

dfp@cbnewsl.ATT.COM (david.f.prosser) (08/24/89)

In article <17504@ut-emx.UUCP> pmaniac@walt.cc.utexas.edu (Noah Friedman) writes:
>To prevent this problem, why not cast the arguments as doubles?
>
>void swap(double *x, double *y) 
>{
>    *x += *y;
>    *y = *x - *y;
>    *x -= *y;
>}
>
>func()
>{
> int a, b;
>
>    ...
>    swap((double *) &a, (double *) &b);
>    ...
>}
>
>This function should then work with any type, providing you type cast.
>Of course, there is the possibility of loss of precision, but this
>only applies to floating point variables.

Because it is wrong.

This call to swap passes pointers to integers converted to pointer-to-
double type.  This does not change the objects pointed-to in any manner.
The *x and *y expressions within swap cause completely undefined behavior.

With most architectures, double objects are bigger than int objects.
The *x and *y subexpressions will be accessing bytes outside of the
ints a and b.  Moreover, the bit patterns in the representation for int
values most likely has little to do with that used by doubles.  It is
quite likely that floating exceptions will occur.  Finally, the initial
premise (using doubles will prevent problems with the add and subtract
swap) is false: it is not guaranteed that precision will not be lost
converting from ints to doubles.  For example, consider an architecture
that has ints and doubles in identical-size objects (possible with ANSI C).
Given that there have to be some bits for the exponent, some loss of
precision is likely.

I do agree with the letter writer than these "tricks" for exchanging
values are all not worth the cost, except in extreme conditions such
as the classic linked list walk and return that XORs pointers so that
O(n) extra pointers don't need to be stored.

Dave Prosser

bright@Data-IO.COM (Walter Bright) (08/24/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu> tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
<To swap two variables x,y in C without using a temporary variable:
<       x += y;
<       y = x - y;
<       x -= y;
<does anyone know an even simpler method?
Known as the 'XOR trick':
	x ^= y;
	y ^= x;
	x ^= y;
or even:
	#asm	XCHG x,y	/* :-) */

karzes@mfci.UUCP (Tom Karzes) (08/24/89)

In article <1061@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
>>        To swap two variables x,y in C without using a temporary variable:
>>        x += y;
>>        y = x - y;
>>        x -= y;
>
>The problem with this method is that it will be easy to overflow the
>variables in the first statement.   For example if x and y are short (16 bit)
>integers and x contains 18,000 and y contains 19,000 the x will overflow to 
>negative territory on the first assignment and throw off the rest of the 
>equations.  If x & y are large enough the overflow could just be lost.

This should only be a problem if your machine traps on integer overflow,
or if your hardware is broken and doesn't give the desired results in
the presence of integer overflow.  Sane hardware will give you the correct
low-order bits of the result regardless of overflow.  This will guarantee
that the above produces correct results, even if the intermediate results
overflow.  So the statement about "throwing off the rest of the equations"
above is incorrect.  In the case of 16-bit integers, you can think of the
entire process as an unsigned computation being performed mod 2**16 (the
only difference between signed and unsigned integer addition, subtraction,
and multiplication is the overflow conditions, provided your hardware always
gives you the correct low-order bits).

In your example, using 16-bit integers:

    action      x (decimal) (hex)           y (decimal) (hex)
    ------      -----------------           -----------------
    initial         18000    4650               19000    4a38
    x += y         -28536    9088               19000    4a38
    y = x - y      -28536    9088               18000    4650
    x -= y          19000    4a38               18000    4650

cpcahil@virtech.UUCP (Conor P. Cahill) (08/24/89)

In article <17504@ut-emx.UUCP>, pmaniac@walt.cc.utexas.edu (Noah Friedman) writes:
> To prevent this problem, why not cast the arguments as doubles?
> 
> void swap(double *x, double *y) 
> {     *x += *y;    *y = *x - *y;   *x -= *y; }
> 
> func()
> {
>  int a, b;
>     swap((double *) &a, (double *) &b);
> }

This would not work, and would probably cause a core drop, because

	1. The swap will always modify sizeof(double) bytes.  a is 
	   sizeof(int) bytes and usually the two are not the same.  Casting
	   an address does NOT effect the data the address refers to.

	2. The data at &a will probably not meet the standard for 
	   representation as a double and would likely cause a floating
	   point exception.

	3. If the data items were doubles, you could still overflow in 
	   the first statement.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9240	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

cpcahil@virtech.UUCP (Conor P. Cahill) (08/24/89)

In article <990@m3.mfci.UUCP>, karzes@mfci.UUCP (Tom Karzes) writes:
> In article <1061@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> >In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:

> This should only be a problem if your machine traps on integer overflow,
> or if your hardware is broken and doesn't give the desired results in
> the presence of integer overflow.  Sane hardware will give you the correct
> low-order bits of the result regardless of overflow.  This will guarantee
> that the above produces correct results, even if the intermediate results
> overflow.


I stand corrected.  You know I was about to say what about unsigned values
where the two operands added up to be greater than what can fit into the
storage area, but I decided to try it on my machine before I opened my big
mouth.  Lucky I did.  Using the following code:

	unsigned short i,j; i = 42000; j = 42001;

	printf("sizeof(i) = %d\n", sizeof(i));

	printf("i = %u, j = %u\n", i, j);
	i += j;
	printf("i = %u, j = %u\n", i, j);
	j = i - j;
	printf("i = %u, j = %u\n", i, j);
	i -= j;
	printf("i = %u, j = %u\n", i, j);

the output was:

	sizeof(i) = 2
	i = 42000, j = 42001
	i = 18465, j = 42001
	i = 18465, j = 42000
	i = 42001, j = 42000

I was about to scream "Compiler Error" when I realized that 18465 - 42001
does underflow back to 42000.

So the original post does work as long as there is no hardware problems
with decimal overflow. 
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9240	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

jon@shaffer.UUCP (Jon Doran/60000) (08/24/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu>, tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:
> 
>        To swap two variables x,y in C without using a temporary variable:
> 
>        /* begin swap */
>        x += y;
>        y = x - y;
>        x -= y;
>        /* end swap */

I don't know about that, seems that overflow is a possibility...

Something that I've used (mainly in assembly code) is:
	x ^= y;
	y ^= x;
	x ^= y;

To verify that the above works (x and y must be the same size of a variable...)
choose appropriate values for x and y, represent these in binary on paper,
then perform the exclusive ors manually.  This is perhaps the best explaination.



Jon Doran
IBM AWD,  Austin TX

news@ism780c.isc.com (News system) (08/25/89)

In article <3040@solo5.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>jsb@advdev.LBP.HARRIS.COM (FLEA) writes:
>\In article <8350@boring.cwi.nl> tromp@piring.cwi.nl (John Tromp) writes:
>\:		 (Timothy R. Gottschalk) writes:
>\...
>\:>       x += y;
>\:>       y = x - y;
>\:>       x -= y;
>\...
>\Sorry, folks, both of these are illegal if x and y are pointers.
>
>Or if they're structs! :-)

It is obvious to the casual observer that the above is illegal if the
operations + and - are not defined for the data.  The question really is: for
the case where the program segment (as written) compiles, will it swap the
values of x and y.  The answer is that it will work on two's complement
binary machines that ignore overflow and carry out provided x and y are the
same integral type.  It does not work when the types differ (for example
char x; long y;).  It also does not work for all values of floating types.

But most important, it is a bad piece of code for two reasons.  1) it is
obtuse and  2) it requires more space and time than the simpiler:

     temp=x; x=y; y=temp;

As may have been pointed the EXOR method may be faster then the above for
a machine like the 370 that provides a memory to memory EXOR operation on
data blocks.  But there is no way to express such an operation in C.

     Marv Rubinstein

thomas@uplog.se (Thomas Hameenaho) (08/25/89)

In article <MYwDEFy00WB842JEUx@andrew.cmu.edu> tg1e+@andrew.cmu.edu (Timothy R. Gottschalk) writes:

	  To swap two variables x,y in C without using a temporary variable:

	  /* begin swap */
	  x += y;
	  y = x - y;
	  x -= y;
	  /* end swap */

	  Just curious...(this looks pretty valid) does anyone know an even
   simpler method?  I would never program this way -- it's more of a theory
   question.  I've been told that it can't be done (???).
   Tim Gottschalk
   Pgh, PA

The problem with this is the possible loss of precision.

(x += y) must not overflow x. Also if the variables are floating types
you could wind up having almost no significant bits left.


A solution that doesn't introduce any loss of precision but only
works for scalar types is:

	x ^= y;
	y = x ^ y;
	x ^= y;

--
Real life:	Thomas Hameenaho		Email:	thomas@uplog.se
Snail mail:	TeleLOGIC Uppsala AB		Phone:	+46 18 189406
		Box 1218			Fax:	+46 18 132039
		S - 751 42 Uppsala, Sweden

cudcv@warwick.ac.uk (Rob McMahon) (08/26/89)

Re: x += y; y = x - y; x -= y; 
vs. x ^= y; y ^= x; x ^= y; 
vs. tmp = x; x = y; y = tmp;

Surely this is another of these things that should be coded legibly and left
to the compiler to do the best way, rather than trying to guess what
operations the current machine has, and whether the compiler has put variables
in memory or registers etc.  Lets talk about how to improve the compilers
first.  On our Gould PN6000 with GCC 1.34

	{
	  int tmp;
	  tmp = x;
	  x = y;
	  y = tmp;
	}

compiles to

	xchg	r5,r4

Rob
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             ARPA:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England

jdchrist@watcgl.waterloo.edu (Dan Christensen) (08/28/89)

In article <184@titania.warwick.ac.uk> cudcv@warwick.ac.uk (Rob McMahon) writes:
>On our Gould PN6000 with GCC 1.34
>
>	{
>	  int tmp;
>	  tmp = x;
>	  x = y;
>	  y = tmp;
>	}
>
>compiles to
>
>	xchg	r5,r4

Just out of curiousity, is space allocated for tmp?

----
Dan Christensen, Computer Graphics Lab,	         jdchrist@watcgl.uwaterloo.ca
University of Waterloo, Waterloo, Ont.	         jdchrist@watcgl.waterloo.edu

wolfgang@ruso.UUCP (Wolfgang Deifel) (08/28/89)

pmaniac@walt.cc.utexas.edu (Noah Friedman) writes:

>void swap(double *x, double *y) 
>{
>    *x += *y;
>    *y = *x - *y;
>    *x -= *y;
>}

>func()
>{
> int a, b;

>    ...
>    swap((double *) &a, (double *) &b);
>    ...
>}

I think, this function never works right. If you cast the adress of
an integer to adress of double, you don't cast the int to double.
What you wanted to do is ( I think ), &((double)a) but this also
doesn't work, because (double)a is an r-value which has no adress.

--
Wolfgang Deifel
Dr. Ruff Software GmbH, 5100 Aachen, Juelicherstr. 65-67, W-Germany
uucp: ...!uunet{!mcvax}!unido!rwthinf!ruso!wolfgang - phone : +49 241 156038

harish@csl.ncsu.edu (Harish Hiriyannaiah) (08/28/89)

 I have been reading the swap() discussion with interest, but I am still
 unconvinced about the XOR trick.  Let's review both of them.

 [1]
	 temp = x;
	 x = y;
	 y = temp;

 [2] 
	 x ^= y;
	 y ^= x;
	 x ^= y;

Advantages of [2]:
 (1) Works for any fundamental data type. (char, int, float etc);
 (2) Does not need allocation for temp.

Advantage (1) is of more value than (2). In terms of speed, both are just
about the same.(assuming that x and y are out in memory - BTW, are there
any processors which implement XCHG for memory too, in addition to
registers ?) The allocation for temp on the stack ( assuming a stack
model ) is negligible in terms of allocation time. But in terms of
readability of the code, [2] fails over [1], unless it is properly
documented, which most people fail to do.

harish pu. hi.					harish@ecelet.ncsu.edu
						harish@ecebucolix.ncsu.edu

cudcv@warwick.ac.uk (Rob McMahon) (08/28/89)

In article <11274@watcgl.waterloo.edu> jdchrist@watcgl.waterloo.edu (Dan Christensen) writes:
>In article <184@titania.warwick.ac.uk> cudcv@warwick.ac.uk (Rob McMahon) writes:
>>On our Gould PN6000 with GCC 1.34
>>	{ int tmp; tmp = x; x = y; y = tmp; }
>>compiles to
>>	xchg	r5,r4
>
>Just out of curiousity, is space allocated for tmp?

It does get a register allocated for it, although of course it is immediately
reusable since tmp goes out of scope straight away.  It is done as a simple
peephole optimisation after register allocation, a better job could probably
be done by spotting the case earlier in the compiler.  My point is that if the
compiler does do anything like this, all you're doing by using deviosities
like `{ x ^= y; y ^= x; x ^= y; }' is confusing the compiler so that it will
miss these optimisations.

Rob
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             ARPA:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (08/29/89)

  At the risk of starting a flamefest the day before I start my
vacation, I will say that the next C standard should *consider* a swap
operator, since there have been so many clever ways posted to sway
regular types, structs, etc.

  My first though is to suggest an operator which will work on two
values of any type. No frills, no extensions. Has to be part of the
language (compiler) to allow generation of fast inline code. I have no
strong objection to using another operator, but would favor making the
sytax swap(x,y) for readability.

  There are lots of ways to do this, but they all seem to lack at least
one of (a) portability to any C machine, (b) speed of execution, or (c)
generality to all data types.

  If you really want to discuss this with me or flame me send mail, my
news might die before I get back.
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

mcdonald@uxe.cso.uiuc.edu (08/29/89)

Just for curiosity, is anyone's compiler smart enough to optimize


temp = x;
x = y;
y = temp;

into an XCHG instruction? What about Fortran compilers on the
equivalent construct?

Doug MCDonald

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (08/29/89)

In article <190@titania.warwick.ac.uk>, cudcv@warwick.ac.uk (Rob McMahon) writes:

|                                                         My point is that if the
|  compiler does do anything like this, all you're doing by using deviosities
|  like `{ x ^= y; y ^= x; x ^= y; }' is confusing the compiler so that it will
|  miss these optimisations.

  You certainly have given a good example. However, there are reasons
for doing tricks such as the XOR thing. They enable me to write a macro
which does the swap for any type. I could still do this by having a
macro for each type, but then the program will break if the type of the
base variable gets changed, say from float to double because I port it
to a machine with minimal float.

  If I had typing by example, such as the "same_as" extension somebody
showed me a year or so ago, I could say:
	{ same_as(x) temp; temp=x; x=y; y=temp; }
as you suggest, although the actual name of the variable might conflict.

  I still like the idea of a swap operator... x<=>y, but without it we
have to use macros or write the explicit and faster code you mentioned.

BTW: why doesn't gcc optimize the common x^=y^=x^=y expression ;-)
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

karl@haddock.ima.isc.com (Karl Heuer) (08/31/89)

In article <230@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
>However, there are reasons for doing tricks such as the XOR thing.  They
>enable me to write a macro which does the swap for any type.

Only for integral types.  It won't work on float, pointer, struct, etc.

If you insist on using a single macro, I think that
	#define swap(x,y,TYPE) {TYPE _swap_tmp_=(x); (x)=(y); (y)=_swap_tmp;}
is a better bet than the XOR hack.

I think if I were proposing a *language change* to solve this problem, I
wouldn't ask for a builtin swap operator; it's too limited.  Might as well
invent something that has other applications as well, such as the displacing
assignment operator (where  x := y  stores value y in lvalue x, but the value
of the entire expression is the previous value of x rather than the new one)
or even my reverse sequential evaluation operator (where  x,,y  evaluates
first x and then y, but (unlike the comma operator) returns y as its value;
cf. `prog1' in lisp).  Then swap would be  x=y:=x  or  x=(y,,y=x)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(Followups on this last paragraph should go to comp.lang.misc, please.)

cik@l.cc.purdue.edu (Herman Rubin) (08/31/89)

In article <14479@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes:
> In article <230@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
> >However, there are reasons for doing tricks such as the XOR thing.  They
> >enable me to write a macro which does the swap for any type.
> 
> Only for integral types.  It won't work on float, pointer, struct, etc.

If one adds a pseudo-op, say use (I will not object to a more appropriate
term) so that (use int)x means treat x as type int no matter what it was,
if possible, then it will work on float and pointer, and even swap between,
say, float and pointer.  If this is modified to allow multiple-word types,
it could handle double and struct.

This is another example of keeping the tools from the programmer.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

chris@mimsy.UUCP (Chris Torek) (09/01/89)

-In article <14479@haddock.ima.isc.com> karl@haddock.ima.isc.com
-(Karl Heuer) writes:
->[The xor trick] won't work on float, pointer, struct, etc.

In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
-If one adds a pseudo-op, say use (I will not object to a more appropriate
-term) so that (use int)x means treat x as type int no matter what it was,
-if possible, then it will work on float and pointer, and even swap between,
-say, float and pointer.  If this is modified to allow multiple-word types,
-it could handle double and struct.
-
-This is another example of keeping the tools from the programmer.

And if one uses a wrench as a hammer, it sometimes (actually often) works.
If you want to swap values, you should swap values.  Icon has a nice
notation for it: `x:=:y'.  C happens not to have a nice notation for it.
(use int) is not very nice either, because it is size dependent.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/01/89)

In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>... so that (use int)x means treat x as type int no matter what it was,

If it wasn't represented with the same number of bits as an int, what
could this possibly mean?  If you're going to invent something, make
sure that it is sufficiently useful first.

>This is another example of keeping the tools from the programmer.

No, this is another example of not knowing how to use the tools that are
already provided.

ok@cs.mu.oz.au (Richard O'Keefe) (09/01/89)

In article <1545@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
> In article <14479@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes:
> > In article <230@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
> > >However, there are reasons for doing tricks such as the XOR thing.  They
> > >enable me to write a macro which does the swap for any type.
> > Only for integral types.  It won't work on float, pointer, struct, etc.
...

> This is another example of keeping the tools from the programmer.

On the 18th of April, 1962, Christopher Strachey said:
	Writing programs needs genuis to save the last order
	or the last millisecond.  It is great fun, but it is
	a young man's game.  You start it with great
	enthusiasm when you first start programming, but after
	ten years you get a bit bored with it, and then you
	turn to automatic-programming languages and use them
	because they enable you to get to the heart of the
	problem that you want to do, instead of having to
	concentrate on the mechanics of getting the program
	going as fast as you possibly can, which is really
	nothing more than doing a sort of crossword puzzle.

I shouldn't need to point out that "the XOR thing" has the extremely
nasty "feature" that swap(x[i], x[j]) will set x[i] to 0 when i = j.

I shouldn't need to point out that some programming languages
(Burroughs Extended Algol, Pop2, Algol 68, Dijkstra's notation)
can do exchanges without XOR hacks, but that these languages remain
in a minority because exchanges are rare and easily avoidable at
low cost.

kim@kim.misemi (Kim Letkeman) (09/01/89)

> A more intriguing (and less obvious) way is to do:
>   /* begin swap */
>   x ^= y;
>   y ^= x;
>   x ^= y;
>   /* end swap */
> 
> Alas, in C, the bitwise OR only works with int's and char's :-(.               
> Of course, you can type-cast, but it doesn't look as neat.  
> 
> Dave Johnson - Computer People Unlimited @ GE Medical Systems.
> 
I hope that all of this talk about swapping two values without a
temporary is just for fun ...

When one writes clean, easy to read code, this sort of idea never
occurs. Simply using a temporary location makes it obvious what is
going on. It would be silly to have to actually comment something as
trivial as "here I am swapping two values".

It might be said (by the non-enlightened) that "it's only three lines
of code ... surely you can figure out what is going on."

This is true, anyone can figure it out by pausing and examining these
in detail. But if they occur in a program of several hundred, or
thousand lines, they are glossed over without any attempt at
understanding them. A critical point in the algorithm could then be
missed. 

Of course, it is possible that one would do this for efficiency's
sake, right? After all, one less temporary variable *must* be more
efficient.

Well ... not on my machine (sunos 4.0.3). 

Here are two code fragments and their assembly output:

	x ^= y;
	y ^= x;
	x ^= y;

	movl    a6@(-0x8),d0
	eorl    d0,a6@(-0x4)
	movl    a6@(-0x4),d0
	eorl    d0,a6@(-0x8)
	movl    a6@(-0x8),d0
	eorl    d0,a6@(-0x4)

	temp = x;
	x = y;
	y = temp;

	movl    a6@(-0x4),a6@(-0xc)
	movl    a6@(-0x8),a6@(-0x4)
	movl    a6@(-0xc),a6@(-0x8)
	                        
As an exercise, these are mildly interesting, but as a coding style,
they suck.
-- 
Kim Letkeman    uunet!mitel!spock!kim

cik@l.cc.purdue.edu (Herman Rubin) (09/01/89)

In article <10897@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
> >... so that (use int)x means treat x as type int no matter what it was,
> 
> If it wasn't represented with the same number of bits as an int, what
> could this possibly mean?  If you're going to invent something, make
> sure that it is sufficiently useful first.

This is absolutely correct.  In my earlier posting, I did say that if
the conventions were extended to multi-"word" items, it could be use
for doubles and structs.  And if the exclusive or instruction (or in
those posters who posted it with + and - the arithmetic instructions)
do not involve the whole word, it will not work, even for those items.

To use these devices to swap items, it is necessary to know that they
work on the whole item.  This is not always so, and, for example, using
+ and - will not work on the CYBER 205/ETA 10 machine.

> >This is another example of keeping the tools from the programmer.
> 
> No, this is another example of not knowing how to use the tools that are
> already provided.

All tools must be used with care.  If the items being swapped overlap, there
are great difficulties with the whole process.  If the items are identical,
these procedures definitely give the wrong answer.

Thou shalt know thy computer's hardware idiosyncracies, lest thou mess up
thy results.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

bill@twwells.com (T. William Wells) (09/01/89)

In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
: In article <14479@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes:
: > In article <230@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
: > >However, there are reasons for doing tricks such as the XOR thing.  They
: > >enable me to write a macro which does the swap for any type.
: >
: > Only for integral types.  It won't work on float, pointer, struct, etc.
:
: If one adds a pseudo-op, say use (I will not object to a more appropriate
: term) so that (use int)x means treat x as type int no matter what it was,

Try: *(int *)&x. If you are feeling particularly nonportable today.

: if possible, then it will work on float and pointer, and even swap between,
: say, float and pointer.

No it won't. At the very least, you would have had to define it as
"as if it were an integer of the appropriate size" in which case,
while the construct will now do something that can't be done quite as
easily, it doesn't add any real utility to the language.

Such a construct would be just as nonportable as the cast above.

Moreoever, you clearly have forgotten, or never learned, that floats,
pointers, ints and most other things have sizes that are not
necessarily equal.

:                          If this is modified to allow multiple-word types,
: it could handle double and struct.

Why bother? The only advantage this silly construct has over the cast
above is its polymorphism; and given the lack of support for that
anywhere else in the language, it is pointless. (No, don't tell me
the language should have all those features. It shouldn't. Why?
Because that would make it a different language: C++.)

: This is another example of keeping the tools from the programmer.

This is yet another example of Mr. Rubin wishing for the moon.

To repeat for the hundredth time: a programming language can not have
all features nor can it be everything to everyone. There are good
theoretical reasons for this and decades of experience to drive home
the point.

Mr. Rubin? Shut up. Your wishes are a waste of our time. You have,
time and again, demonstrated your fuzzy thinking and your ignorance
of the most elementary considerations. You are an idiot. And a fool.

Get lost. Develop some humility. Learn this language you keep
carping, ignorantly, about, and then _maybe_ you will have something
useful to say.

Followups have been directed to alt.flame.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

dg@lakart.UUCP (David Goodenough) (09/02/89)

karl@haddock.ima.isc.com (Karl Heuer) sez:
> I think if I were proposing a *language change* to solve this problem, I
> wouldn't ask for a builtin swap operator; it's too limited.  Might as well
> invent something that has other applications as well, .....

Why not use the BCPL comma operator:

	x, y = y, x;

I'd just suggest some other separator ('$' pops readily to mind), so you'd
have:

	x $ y = y $ x;

Now, when used in an expression, what value does it return, nex x or new y??

This could (of course) be expanded to things such as:

	x $ y $ z = y $ z $ x;

to do a three way rotation of variables.

Well, enough rambling from a deranged mind (just because I cut my teeth on
BCPL :-) ).
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com			  +---+

scs@hstbme.mit.edu (Steve Summit) (09/03/89)

In article <1547@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>Thou shalt know thy computer's hardware idiosyncracies, lest thou mess up
>thy results.

Thou shalt use high-order languages wisely, lest the rest of thy
days be spent in needless toil over hardware idiosyncracies.

diamond@csl.sony.co.jp (Norman Diamond) (09/04/89)

In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:

>If one adds a pseudo-op, say use (I will not object to a more appropriate
>term) so that (use int)x means treat x as type int no matter what it was,
>if possible, then it
 [the XOR trick]
>will work on float and pointer, and even swap between,
>say, float and pointer.  If this is modified to allow multiple-word types,
>it could handle double and struct.
>This is another example of keeping the tools from the programmer.

The way to write this pseudo-op in C is:

   *(int*)&x

It still doesn't work if x is longer than an int.  Most hardware does
not supply tools for performing XOR on floating-point registers.  When
Mr. Rubin designs his language, he will have to design a machine to
run it on too.

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

cik@l.cc.purdue.edu (Herman Rubin) (09/05/89)

In article <10790@riks.csl.sony.co.jp>, diamond@csl.sony.co.jp (Norman Diamond) writes:
> In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
> 
> >If one adds a pseudo-op, say use (I will not object to a more appropriate
> >term) so that (use int)x means treat x as type int no matter what it was,
> >if possible, then it
>  [the XOR trick]
> >will work on float and pointer, and even swap between,
> >say, float and pointer.  If this is modified to allow multiple-word types,
> >it could handle double and struct.
> >This is another example of keeping the tools from the programmer.
> 
> The way to write this pseudo-op in C is:
> 
>    *(int*)&x

What if x is in a register?  Much of the time things will be in registers.
Indeed, on some machines, arithmetic operations can only be done using
registers.  One might not even have memory to memory moves.  On such machines,
there is no point in attempting to swap two items in memory by other than
moving both to registers and storing the registers, or memory and register
by other than using a spare register.  But the situation with few spare
registers and a register-register swap wanted is much more common.

> It still doesn't work if x is longer than an int.  Most hardware does
> not supply tools for performing XOR on floating-point registers.  When
> Mr. Rubin designs his language, he will have to design a machine to
> run it on too.

Quite a few machines do not have separate floating-point registers.  On
those, the swap is appropriate for XOR-sized items.  And on a double
length operand, two XORs might be the best way to do it, etc.  This
is again especially important if registers are scarce.

This problem is a good example of the need to consider that the way to
perform operations on quantities may depend on not only the types of the
arguments, but also upon where they are stored.

The machine language programmer has no problems with this.  The hardware
limitations are machine dependent.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

peter@ficc.uu.net (Peter da Silva) (09/05/89)

In article <1560@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
> In article <10790@riks.csl.sony.co.jp>, diamond@csl.sony.co.jp (Norman Diamond) writes:
> >    *(int*)&x

> What if x is in a register?

What if it is? This is a quality-of-implementation issue. A good optimiser
will cancel out all the extra loads and stores. I'm sure you wouldn't bother
with a compiler with a poor optimiser...
-- 
Peter da Silva, *NIX support guy @ Ferranti International Controls Corporation.
Biz: peter@ficc.uu.net, +1 713 274 5180. Fun: peter@sugar.hackercorp.com. `-_-'
"The Distribution: field on the header has been modified so as not to      'U`
 violate Information Export laws." -- eugene miya, NASA Ames Research Center.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/05/89)

In article <1560@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>The machine language programmer has no problems with this.

Neither does the high-level language programmer, who has been swapping
the contents of variables for years.  It is only someone with an
excessive concern for controlling the details of the generated code
from the compiler who has a problem, and he should be programming in
assembly language if the details truly matter.

diamond@csl.sony.co.jp (Norman Diamond) (09/06/89)

In article <10790@riks.csl.sony.co.jp>, I wrote:

>>>    *(int*)&x

In article <1560@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:

>> What if x is in a register?

In article <6029@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:

>What if it is? This is a quality-of-implementation issue. A good optimiser
>will cancel out all the extra loads and stores. I'm sure you wouldn't bother
>with a compiler with a poor optimiser...

Actually Mr. Rubin was (almost) right, for a change.  He meant, what if
x is declared as register.  It's illegal to apply & to a register even
if no loads or stores are generated.  If a particular implementation
allowed it after a suitable warning, would that be an advantage or a
(portability-discouraging) disadvantage?

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

jeffrey@algor2.algorists.com (Jeffrey Kegler) (09/06/89)

One thing that makes

A)   #define swap(x,y) (x ^= y, x ^= y ^= x)

seem more attractive than

B)   #define swap(x,y) {int tmp; tmp = x; y = tmp; x = y; }

is the syntax.

Consider

  if (...) swap(x,y);
  else { do stuff ...; swap(a,b); }

which the Solution A allows, but which won't work with the Solution B,
unless the first semi-colon is omitted.  The second last semi-colon in
the above example is misleading, but overwise harmless.

Even more disastrous for B is

  for (tweedledee=1, tweedledum=0; !done; swap(tweedledee, tweedledum)) {
    stuff ...

Notes:
1) Both solutions are taken from other postings and not tested.
2) Solution A should have more parentheses, they are omitted for clarity.
3) It is assumed all variables are ints.
4) I think the idea of a global temporary to make Solution B an expression
is unworkable if your global temporary has its name used elsewhere
and ugly when it does work.
5) Defines are prefered because inlining the solutions makes the code harder
to read, and the overhead of a function call to swap two ints is often not
justifiable.
-- 

Jeffrey Kegler, Independent UNIX Consultant, Algorists, Inc.
jeffrey@algor2.ALGORISTS.COM or uunet!algor2!jeffrey
1762 Wainwright DR, Reston VA 22090

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/06/89)

In article <6029@ficc.uu.net>, peter@ficc.uu.net (Peter da Silva) writes:
|  In article <1560@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
|  > In article <10790@riks.csl.sony.co.jp>, diamond@csl.sony.co.jp (Norman Diamond) writes:
|  > >    *(int*)&x
|  
|  > What if x is in a register?
|  
|  What if it is? This is a quality-of-implementation issue. A good optimiser
|  will cancel out all the extra loads and stores. I'm sure you wouldn't bother
|  with a compiler with a poor optimiser...

  I wouldn't bother with a compiler which allowed me to take the address
of a register variable, either. On a quality of implementation scale I
rate that as zero.

  This brings to mind a good point, that implementation of a swap should
not bypass any internal checking, such as 'const' declarations.
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

karzes@mfci.UUCP (Tom Karzes) (09/07/89)

In article <1989Sep6.061301.17629@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
>One thing that makes
>
>A)   #define swap(x,y) (x ^= y, x ^= y ^= x)
>
>seem more attractive than
>
>B)   #define swap(x,y) {int tmp; tmp = x; y = tmp; x = y; }
>
>is the syntax.

Not to mention the fact that B) doesn't work.  Perhaps you meant:

    #define swap(x,y) {int tmp; tmp = x; x = y; y = tmp;}

One advantage of this over A) is that swap(a,a) works.  More realistically,
swap(a[i],a[j]) works when i == j.  Another advantage is that, though
amusing, A) is absurd, likely to be inefficient, and likely to inhibit
optimization.

As far as style goes:  When macros are written which should be thought of
as statements, then they should have the syntax of statements.  Yes, it's
a bit ugly, but a good naming convention will make it obvious that the macro
is in fact a macro.  The problem is that function references, which in many
contexts are thought of as statements, are really just expressions, and a
semicolon is needed to turn the expression into a statement.

If you want swap to be a statement with no defined result value, then
you should not be required to supply a semicolon to make it a statement.
Otherwise, if it is to be an expression with a defined value, then
it should be like any other expression and require a semicolon to
make it a statement.  Unfortunately, in this case you can't use a block
(i.e., a compound statement) because they aren't expressions in C and
hence cannot have result values.

>4) I think the idea of a global temporary to make Solution B an expression
>is unworkable if your global temporary has its name used elsewhere
>and ugly when it does work.

Well, I'll agree that it's a bit ugly, but it certainly isn't unworkable.
If you'll recheck the example, you'll see that the temporary is not
global, but is local to the block defined by the macro.  You therefore
only have to ensure that it doesn't conflict with any name used in x
or y.  This is easily accomplished by prefixing the name with some
prefix which is "owned" by the swap macro.  For example, if you call
the macro SWAP and designate any identifier beginning with SWAP_ as
being private to the swap macro, then you could use the following with
no risk of name conflict:

#define SWAP(x,y) {int SWAP_tmp; SWAP_tmp = x; x = y; y = SWAP_tmp;}

You could even make SWAP_tmp a global if you wanted, although this would
probably force your compiler to keep it in memory.

bobmon@iuvax.cs.indiana.edu (RAMontante) (09/07/89)

jeffrey@algor2.UUCP (Jeffrey Kegler):
-
-B)   #define swap(x,y) {int tmp; tmp = x; y = tmp; x = y; }
-
-Consider
-
-  if (...) swap(x,y);
-  else { do stuff ...; swap(a,b); }
-
-which the Solution A allows, but which won't work with the Solution B,
-unless the first semi-colon is omitted.  The second last semi-colon in
-the above example is misleading, but overwise harmless.


gcc accepts the following:

#define swap(a,b)	({int t; t=(a); (a)=(b); (b)=t;})

and the trailing semicolon should be okay here as it follows a
parenthesized expresssion.

dwh@twg-ap.UUCP (Dave Hamaker) (09/08/89)

From article <922@kim.misemi>, by kim@kim.misemi (Kim Letkeman):
> I hope that all of this talk about swapping two values without a
> temporary is just for fun ...
> 
> When one writes clean, easy to read code, this sort of idea never
> occurs. Simply using a temporary location makes it obvious what is
> going on. It would be silly to have to actually comment something as
> trivial as "here I am swapping two values".

Whenever _I_ write code for swapping two values, this idea _always_
occurs, and I usually decide not to apply it.  Does this mean I write
dirty, hard to read code?

I can also assure you that every piece of code you've ever written
would be hard to read -- for my five-year-old daughter.

The position that good programming is a matter of following the right
set of moralistic rules is, in my view, oversimplified to the extent
of being simply wrong.  Good writing generally requires:
     1) Knowing your subject.
     2) Knowing the language.
     3) Knowing your audience.
     4) As well as knowing principles of "clear" writing.

When you write a program, you have more than one audience.  You are writing
for at least one machine, for at least one compiler (if you use a high-level
language), as well as for those people who will read it later (including
yourself).  If you aim too low for the people audience, you may find that
the people who really read your code may find it "cluttered" with trivial
comments.  You might even be accused of wasting your time writing them.

If you ignore your other audiences, there's nothing wrong with always
choosing the algorithm which is easiest to explain.

The exclusive-or technique for exchanging two data items really falls in
the area of knowing your subject.  It's part of understanding the uses of
bitwise logical operations, which is important for some kinds of program-
ming.  I can easily imagine a few cases where it might be the "right"
solution to a programming problem, although the trick is obscure enough
that uncommented use of it is probably always wrong.

If we're going to look at generated code, it might be instructive to
see what happens if x and y are declared to be "register" (I say this
without actually knowing what will come out of the compiler).

-Dave Hamaker
The Wollongong Group
...!sun!amdahl!twg-ap!dwh
dwh@twg.com

condict@cs.vu.nl (medewerker ast) (09/11/89)

In article <1989Sep6.061301.17629@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
 |One thing that makes
 |
 |A)   #define swap(x,y) (x ^= y, x ^= y ^= x)
 |
 |seem more attractive than
 |
 |B)   #define swap(x,y) {int tmp; tmp = x; y = tmp; x = y; }
 |
 |is the syntax.
 |
 |Consider
 |
 |  if (...) swap(x,y);
 |  else { do stuff ...; swap(a,b); }
 |
 |which the Solution A allows, but which won't work with the Solution B,
 |unless the first semi-colon is omitted.

As has been described several times in this newsgroup, this defect can be
avoided by using one of the following two equivalent definitions instead of
(B), above:

    B1) #define swap(x,y) do {int tmp; tmp = x; y = tmp; x = y; } while (0)
    B2) #define swap(x,y) if (1) {int tmp; tmp = x; y = tmp; x = y; } else 0

This has the advantage of producing a syntax error if the use of swap is not
followed by a ';', just as a real function call would.  It has the disad-
vantage of looking silly and inefficient to the uninitiated.  It should,
however, generate the same code as without the extraneous statement, on any
reasonable C compiler.

Mike Condict			condict@cs.vu.nl
Vrije University

hls@rwthbs.UUCP (H.L. Stahl) (09/12/89)

In article <10897@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
> ...
>
>>This is another example of keeping the tools from the programmer.
>
>No, this is another example of not knowing how to use the tools that are
>already provided.
^^^^^^^^^^^^^^^^^^^^^^^^^^^ VERY TRUE!

And by the way: why do you need an operator for swapping?

if it is for int, float, ..., it is quite simple; if it is for any structure,
you should better use pointers instead, which is faster.


Hans-Ludwig Stahl, Lehrstuhl fuer Betriebssysteme, RWTH Aachen
    |  _           Kopernikusstr. 16, D-5100 Aachen, ..49-(0)241- 80 76 34
    |_|_`__        > Domain:      hls@informatik.rwth-aachen.de
      | |__)       > uucp:        ...!{seismo,mcvax,uunet}!unido!rwthinf!hls
        |__)       > EARN/BITNET: HLS@DACTH01

bph@buengc.BU.EDU (Blair P. Houghton) (09/15/89)

In article <604@rwthbs.UUCP> hls@rwthbs.UUCP (H.L. Stahl) writes:
>In article <10897@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>>In article <1545@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>>>
>>>This is another example of keeping the tools from the programmer.
>>
>>No, this is another example of not knowing how to use the tools that are
>>already provided.
>^^^^^^^^^^^^^^^^^^ VERY TRUE!

Bzzzzzt!  Herm knows how to swap.  He wants super-swapping.

Puts me in the mind of one of these people who've moved from E. Germany
to W. Germany in the past couple of days.  He's a butcher, and the
network news showed him taking a look at the butcher shop in the local
market, and he looked like he would go mad:  everything was automatic,
computer-controlled, had an LED readout, etc.  Now, this fellow may
have been an artist with the tools he had back home, but it's likely
the thought of all the work he could get done and the quality he could
create by employing these machines impressed him no end.

Is it still a matter of skill over availability?

>And by the way: why do you need an operator for swapping?

Because if a machine can do it with a coupla gates and half a cycle,
I'd like to do it with an operator.

Some machines (we've already seen an example involving a DG) have
opcodes to swap two values, and it seems a bit ludicrous to code
some elaborate swapping routine when the optimizer is just going
to throw it all out and insert the single instruction.

At least having the operator ensures that the most efficient swapping
method is systematically defined for any processor.

Still, any good optimizer will catch all the obvious cases, but it's
gotta be harder to write a compiler to do it that way than to implement
just another canned routine.

So why haven't the compiler writers been asking for a swap operator or
keyword?

				--Blair
				  "And don't whine back 'so what
				   are the semantics?' or I'll sic
				   my additive pointer on you."

lmb@ghoti.uucp (Larry Breed) (09/16/89)

A good compiler will produce better code for the naive algorithm than
can be produced for any xor technique.  Here's the code generated by
the Metaware compiler on AOS (IBM's 4.3 for the rt pc).  

#void swap(int* i, int* j)
_.swap:
#{
#   int t;
#   t=*i;
        ls      r0,0(r3)
#   *i=*j;
        ls      r4,0(r2)
        sts     r0,0(r2)
#   *j=t;
        brx     r15		# branch with execute of following instruction
#}
        sts     r4,0(r3)


Disclaimer: Don't blame my employer, blame:
Larry Breed			(415) 855-4460
uucp: uunet!ibmsupt!lmb		inet: ibmsupt!lmb@uunet.uu.net

hls@rwthbs.UUCP (H.L. Stahl) (09/19/89)

In article <4151@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>[...]
>some elaborate swapping routine when the optimizer is just going
>[...]
           ^^ swapping in america seems so much harder than in europe !


                                         -- the butcher

ray@philmtl.philips.ca (Raymond Dunn) (09/20/89)

In article <4151@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>>And by the way: why do you need an operator for swapping?
>
>Because if a machine can do it with a coupla gates and half a cycle,
>I'd like to do it with an operator.

This sounds dangerously like the arguments made by Herman Rubin that 'C'
should provide facilities to access all the functionality of the machine
architecture in some direct way.

Since when was that the goal of *any* language other than assemblers?

Which particular architecture is the source of these language features?
-- 
Ray Dunn.                    | UUCP: ray@philmt.philips.ca
Philips Electronics Ltd.     |       ..!{uunet|philapd|philabs}!philmtl!ray
600 Dr Frederik Philips Blvd | TEL : (514) 744-8200  Ext : 2347 (Phonemail)
St Laurent. Quebec.  H4M 2S9 | FAX : (514) 744-6455  TLX : 05-824090

tneff@bfmny0.UU.NET (Tom Neff) (09/20/89)

In article <714@philmtl.philips.ca> ray@philmtl.philips.ca (Raymond Dunn) writes:
>This sounds dangerously like the arguments made by Herman Rubin that 'C'
>should provide facilities to access all the functionality of the machine
>architecture in some direct way.
>
>Since when was that the goal of *any* language other than assemblers?

Examples do exist.  PL/M-86 and BLISS come to mind.  Every so often
someone at a big computer company decides that assembler is too
dangerous for systems programmers to use (I don't necessarily disagree)
and comes up with a higher level language that has to-the-metal
facilities built in.

These are seldom portable however!  To the extent that C strives for
portability such things shouldn't be built in.

However I would enjoy using specific implementations that offered
optional bare-machine extensions for systems and driver work.  The
"#pragma builtin" approach is usually good enough.
-- 
'We have luck only with women --    \\\     Tom Neff
          not spacecraft!'         *-((O    tneff@bfmny0.UU.NET
 -- R. Kremnev, builder of FOBOS      \\\   uunet!bfmny0!tneff (UUCP)

diamond@csl.sony.co.jp (Norman Diamond) (09/21/89)

In article <714@philmtl.philips.ca> ray@philmtl.philips.ca (Raymond Dunn) writes:

>>This sounds dangerously like the arguments made by Herman Rubin that 'C'
>>should provide facilities to access all the functionality of the machine
>>architecture in some direct way.
>>Since when was that the goal of *any* language other than assemblers?

Actually, a recent posting pointed out that many of the features that
made it into C and even Fortran *did* come about because of this goal.
Only perhaps the goal was not stated as such.

In article <14706@bfmny0.UU.NET> tneff@bfmny0.UU.NET (Tom Neff) writes:

>Examples do exist.  PL/M-86 and BLISS come to mind.  Every so often
>someone at a big computer company decides that assembler is too
>dangerous for systems programmers to use (I don't necessarily disagree)
>and comes up with a higher level language that has to-the-metal
>facilities built in.

Well, PL/M wasn't such a good example of this.  Intel's assembler is a
higher-level language than PL/M, and easier to use!

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/21/89)

  I don't agree that all of the features of the hardware should be in C
(or any other portable langauage), but swap is certainly a widely useful
operation in computer programs, and it could be represented by an
operator, thereby eliminating the need for all of the fancy, obscure,
and possibly non-portable things posted to the net in the last month or
so.

  I would be willing to bet that there are more uses of swap than shift
in applications programs, and yet we have shift. I don't believe that
the addition would make the language too large for any reasonable
computer (it adds about 100 bytes to a similar language which will run
in 64k on CP/M.

-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

rang@cs.wisc.edu (Anton Rang) (09/21/89)

In article <433@crdos1.crd.ge.COM> davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) writes:
>  I would be willing to bet that there are more uses of swap than shift
>in applications programs, and yet we have shift.

  Shift can't be portably represented in a language without it; there
is no (simple) sequence of statements which will do a shift.  The
simple sequence:

		t = x;
		x = y;
		y = t;

will do a swap.  A reasonable compiler (on a reasonable machine) ought
to discover that T is only used in these three statements, and put it
in a register.  At this point, a peephole optimizer ought to discover
that there is a swap instruction applicable.

		MOVE X, R0
		MOVE Y, X
		MOVE R0, Y

can be transformed into

		SWAP X, Y

if the value in R0 is not used past this point.

			Anton
   
+----------------------------------+------------------+
| Anton Rang (grad student)        | rang@cs.wisc.edu |
| University of Wisconsin--Madison |                  |
+----------------------------------+------------------+

"You are in a twisty little maze of Unix versions, all different."

news@ism780c.isc.com (News system) (09/22/89)

In article <714@philmtl.philips.ca> ray@philmtl.philips.ca (Raymond Dunn) writes:
>This sounds dangerously like the arguments made by Herman Rubin that 'C'
>should provide facilities to access all the functionality of the machine
>architecture in some direct way.
>
>Since when was that the goal of *any* language other than assemblers?

It used to be the goal.  FORTRAN had statements like:

      IF SENSE SWITCH  -- gave access to switches on the operators console
      SENSE LIGHT      -- to turn on a light on the operators console
      IF OVERFLOW      -- gave access to alu overflow state
      REWIND n         -- generated a single machine instruction
      ABS(X)           -- generated a single machine instruction
      SIGN(A,B)        -- the IBM/704 had a shift instruction which had the
			  effect of copying a sign from one register to
			  another.
      MIN(A,B,...)     -- generated two instructions for each operand
      PAUSE n          -- A single instruction, displayed 'n' in lights
			  on the operator console.  The operator could
			  continue execution by pressing a start button.
			  PAUSE was intended to be used for console debugging

With the exception of REWIND, these 'features' were all put into the language
because they were 'easy' to implement and provided direct access to hardware.
(I wonder if SIGN is used in any FORTRAN program outside a test suite :-)

Since those days, language designers tend to put only generic facilities into
the language.  One reason C exists on so many machines is that it does NOT
have access to the 'features' of a machine.

     Marv Rubinstein

bph@buengc.BU.EDU (Blair P. Houghton) (09/22/89)

In article <714@philmtl.philips.ca> ray@philmtl.philips.ca (Raymond Dunn) writes:
>In article <4151@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>>Because if a machine can do it with a coupla gates and half a cycle,
>>I'd like to do it with an operator.
>
>This sounds dangerously like the arguments made by Herman Rubin that 'C'
>should provide facilities to access all the functionality of the machine
>architecture in some direct way.

What is this, the Nuremberg-defense rebuttal?  ( :-) )

The issue I'd like to address is that there are some constructs
that seem entirely obvious, but that are not a part of my favorite
language.  Some of them aren't there because there's no rational
way to implement them in a compiler.  A swap-operator, however,
is not at all that way.

Swapping a couple of variables is the utter basis of (almost) all sorting
algorithms.  Every one of them (except hashing) depends on the machine's
ability to put things A and B into places B and A, respectively, and
at least meta-simultaneously.  (I can see Gwyn salivating in the
background...maybe someone should throw him a pointer-sum...)  

I don't see a need for explicit register loading, PC munging, or
even specific selection of the method of addressing objects.  I think
the concepts of 'near' and 'far' are too chummy with the hardware, to
paraphrase some bigwig in the biz.

>Since when was that the goal of *any* language other than assemblers?

Swapping is a data operation, nor specifically a CPU-defined operation.
I bet it doesn't even require the CPU, just a very smart MMU.  There
are (as we've seen) plenty of ways, whether straightforward or
obfuscated-but-extra-efficient, to accomplish it.  Selection of the
optimal method should be up to the compiler, which shouldn't have to be
in -O mode to get it right.  C is almost silly to have omitted it.

>Which particular architecture is the source of these language features?

In this case, it's (allegedly) a Data General; a DG-6000, I think.
Someone used it in an early example in this thread of discussion.
He showed some C that the compiler had turned into a single-instruction
using the swap-opcode.

I thought, as soon as I saw that, "why does it take a special and
expensive pile of optimization algorithms to recognize a swap,
then replace it with this one instruction?"

It shouldn't.  You should just say ( a swap_op b ) and let fly.

We could even use the @-character.  It looks a little like it's twirling
around, anyway.

				--Blair
				  " 'a @ b' or fight!"

ok@cs.mu.oz.au (Richard O'Keefe) (09/22/89)

In article <4310@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes:
> The issue I'd like to address is that there are some constructs
> that seem entirely obvious, but that are not a part of my favorite
> language.  Some of them aren't there because there's no rational
> way to implement them in a compiler.  A swap-operator, however,
> is not at all that way.

Swapping is a special case of the concurrent assignment operator.
If someone were to invest the time in hacking a compiler, I'd much rather
they worked on doing
	i, j, x := i+1, j-1, f(i, j)
efficiently.  Give me that, and
	x, y := y, x
is easy, and avoids flames from people who spell swap "swop".

> Swapping a couple of variables is the utter basis of (almost) all sorting
> algorithms.

This turns out not to be the case.  For example, an efficient version of
``Quick''sort would not use exchanges, even if the machine had them.
Hoare explained this optimisation back in 1962, and it's in Sedgewick's
Acta Informatica paper.  The significantly more efficient merge sort has
no use at all for exchanges.  Radix sort doesn't use them.  Distributed
partitioning sort can manage just fine without them.

If C libraries have managed with a sorting method (quick sort) which was
KNOWN to be slow when it was first invented, I think it's clear that
the speed of sorting is not a priority for C programmers.

Don't get me wrong, I _like_ exchanges.  I liked having them in Algol 68,
and I liked READLOCK in B6700 Algol (to get an exchange, you did
	DEFINE SWOP(X,Y) = X := READLOCK(X, Y);
and you just didn't worry about locking out other processors for one memref).
But if we were talking extensions, I would much rather have a portable way
of making *sure* that I got the errno appropriate to a failed system call
(such as HP-UX's method that was posted some time ago), and I would really
love a standard set of errno names.

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/22/89)

In article <33719@ism780c.isc.com>, news@ism780c.isc.com (News system) writes:

|        IF SENSE SWITCH  -- gave access to switches on the operators console

  This was the way we read environment variables. There were 22
switches, read into our 22 bit words.
|
|        SENSE LIGHT      -- to turn on a light on the operators console

  Dynamic display of program trace, stack usage, etc.

  We had the right ideas 30 years ago, just not the right names for
them. What good is a system with no blinking lights?
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

ray@philmtl.philips.ca (Raymond Dunn) (09/23/89)

In article <433@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
 >  I don't agree that all of the features of the hardware should be in C
 >(or any other portable langauage), but swap is certainly a widely useful
 >operation in computer programs, and it could be represented by an
 >operator, thereby eliminating the need for all of the fancy, obscure,
 >and possibly non-portable things posted to the net in the last month or
 >so.

But this is exactly the argument put forth by Herman for his various "widely
useful operations".

There is no doubt that swap is a common and useful function that is missing as
a primitive in 'C'.  Equally, there are many more.

The discussion is obviously a religious one - where should the line be drawn.
As such, it is probably not going to be profitable.

-- 
Ray Dunn.                    | UUCP: ray@philmt.philips.ca
Philips Electronics Ltd.     |       ..!{uunet|philapd|philabs}!philmtl!ray
600 Dr Frederik Philips Blvd | TEL : (514) 744-8200  Ext : 2347 (Phonemail)
St Laurent. Quebec.  H4M 2S9 | FAX : (514) 744-6455  TLX : 05-824090