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