dmh@mit-borax.ARPA (David Harmon) (04/17/86)
Nice timing...Steve Summit's letter about jumping into blocks arrived just as I had finished debugging a routine which I actually wrote in Pascal and just translated into C for practice. You guessed it, it jumps into a loop, and I honestly don't think there is a way to avoid the goto without some VERY ugly code to keep track of the program's state. The problem is that I need to print out all the elements of a set capable of containing or not containing any value from 0..255. (In Pascal, a SET OF 0.255) That in itself would be no problem given the IN operator, but I also wanted to contract adjacent members of a set into a range syntax. Assume that the include file "nastydefs" contains the definitions of the set type and in() function. Can any of you figure out a way to do this elegantly without the goto? Especially this may involve the break or continue statements...I have looked at possibilities but I must admit I probably don't know a lot of tactics involving them. Also, with an appropriate include file, this procedure both compiles and passes lint. Dave Harmon dmh@mit-borax.arpa dmh@borax.lcs.mit.edu /* Assume the existence of a type named "set", which is intended to simulate the Pascal TYPE KeySet:SET OF 0..255; Further assume the existence of a function in(e,l); set *l; char e; which returns a boolean 1 iff _e_ is an element of _*l_. */ #include <stdio.h> #include "/usr/dmh/nastydefs" wrtlist (listp) set *listp; /*This routine should print out a list of the members of List, with adjacent members shown contracted as N-M, where N and M are the bounds of a range of members. Notice the GOTO statement which gives the effect of two *crossed* loops with a Write and a conditional increment shared by both. Note that the potential member 0 is not used by the application. */ #define MAX NUM_KEYWORDS /*The highest element in use by the application*/ { unsigned char i; set list; i=0; list= *listp; do { putchar(' '); do { if (i=MAX) return(0); else i++; } while (in(i,&list)); cross: /*Beginning of GOTO Loop and shared section*/ printf("%d",i); if (i=MAX) return(0); else i++; } while (in(i,&list)); putchar('-'); while ( (i<MAX) && (in(i+1,&list) ) ) i++; goto cross; /*End of GOTO Loop*/ } /*WriteKList*/
franka@mmintl.UUCP (Frank Adams) (04/19/86)
In article <69@brl-smoke.ARPA> dmh@mit-borax.ARPA writes: > > Nice timing...Steve Summit's letter about jumping into blocks arrived >just as I had finished debugging a routine which I actually wrote in Pascal >and just translated into C for practice. You guessed it, it jumps into a >loop, and I honestly don't think there is a way to avoid the goto without >some VERY ugly code to keep track of the program's state. It just takes one variable, and isn't ugly at all. /* Assume the existence of a type named "set", which is intended to simulate Further assume the existence of a function in(e,l); set *l; char e; which returns a boolean 1 iff _e_ is an element of _*l_. */ #include <stdio.h> #include "/usr/dmh/nastydefs" wrtlist (listp) set *listp; /*This routine should print out a list of the members of List, with adjacent members shown contracted as N-M, where N and M are the bounds of a range of members. Notice the absence of any GOTO statements */ #define MAX NUM_KEYWORDS /*The highest element in use by the application*/ #define NONE -1 { unsigned char i; set list; int last = NONE; /* last is the start of the current string of consecutive members, or -1 if not in such a string */ /* loop through the possible elements of the set, seeing which are in it */ for (i = 0; i <= MAX; i += 1) { if (in(i, &list)) { /* element of set; if not in a sequence, start one */ if (last = NONE) last = i; } else { /* not an element; output preceding sequence, if any */ putrange(last, i-1); last = NONE; } } /* output sequence at end of possible range, if any */ putrange(last, MAX); return; } /* This routine outputs a sequence of consecutive elements in the set. There are three cases: 1) the sequence has no elements. In this case, start will be -1, and nothing should be output 2) the sequence has a single element. In this case, start will equal end, and should be output. 3) the sequence has more than one element. In this case, start should be output, followed by a dash, then end. */ static void putrange(start, end) int start, end; { if (start != NONE) { printf(" %d", start); if (start != end) { printf("-%d", end); } } return; } There. That's not only better structured than your program, it's shorter. Disclaimer: I have not attempted to compile the above program, nor run it through lint. It may, therefore, contain errors. Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Multimate International 52 Oakland Ave North E. Hartford, CT 06108
jpn@teddy.UUCP (John P. Nelson) (04/19/86)
>Can any of you >figure out a way to do this elegantly without the goto? Wow! That code was UGLY! How about this: #include "nastydefs" #define MAX NUM_KEYWORDS /* This routine should print out a list of the members of List, with adjacent * members shown contracted as N-M, where N and M are the bounds of a range of * members. */ wrtlist(listp) register set *listp; { register int i; /* scan entire set */ for (i = 1; i < MAX; ++i) /* note: could just as easily start at 0 */ { if (in(i, listp)) { /* this is the start of a run (potential 1 element run) */ printf("%d", i); /* check for two in a row */ if (++i < MAX && in(i, listp)) { /* at least two in the run - scan to the end */ for (++i; i < MAX; ++i) if (!in(i, listp)) break; printf("-%d", i - 1); } } /* current i is known to NOT be in the set */ } } I assumed that the "in" function was expensive - any element is only checked ONCE. The secret is that the outermost level loop index is modified. A version with an auxiliary index is also possible, which is possibly slightly cleaner.
guido@boring.UUCP (04/19/86)
Dave Harmon obviously doesn't know C and didn't bother to test the C version of his example: it contains i=MAX instead of i==MAX and while(in(..)) instead of while(!in(...)) -- the latter no doubt stemming from a slavish translation of Pascal's until <condition>. Nevertheless, his problem is not one that's solved better with the use of goto's. Here's my code (tested -- it didn't need debugging :-). wrtlist(s) set *s; { int count= 0; /* Counts elements in range currently being printed */ int e; for (e= 0; e <= MAX; ++e) { if (in(e, s)) { if (count == 0) printf(" %d", e); ++count; } else { if (count > 1) printf("-%d", e-1); count= 0; } } } -- Guido van Rossum, CWI, Amsterdam <guido@mcvax.UUCP>
chris@umcp-cs.UUCP (Chris Torek) (04/20/86)
In article <6879@boring.UUCP> guido@mcvax.UUCP (Guido van Rossum) writes: >Here's my code (tested -- it didn't need debugging :-). Oh? What does yours print when all elements (0 through MAX inclusive) are members of the set? (Your code works if MAX is beyond the last member of the set and `in' handles an out-of-range value; but you did not say whether that was indeed the case.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
HARGED%ti-eg.csnet@CSNET-RELAY.ARPA (04/21/86)
To Dave Harmon: I've got a couple of comments about the code you posted to the net last week. I wish you had compiled and run the code you posted. There are some vestigal remnants of its previous incarnation as a Pascal program that keep it from compiling and running correctly. Listed below is the version I used in my tests. /*************************************************************************/ static int wrtlist (list) set list; { unsigned int i=0; do { putchar (' '); do { if (i == MAX) /* please note equality operator */ return (0); else i++; } while (!in (i, list)); /* both looping forms iterate */ /* when the condition is TRUE */ cross: printf ("%d", i); if (i == MAX) return (0); else i++; } while (!in (i, list)); putchar ('-'); while ((i < MAX) && (in (i+1, list))) i++; goto cross; } /*************************************************************************/ Below is a version I came up with that is structured; i.e. all control constructs are single-entry, single-exit. Please note the absence of boolean state variables. /*************************************************************************/ static void wrtlist2 (list) set list; { /* Scan the set represented by list, printing the members that * are present. If two or more consecutive members are present * then print them as a range represented by X-Y where X is * the first member and Y is the last member of the range. */ unsigned int i=0; while (i < MAX) { /* scan whole set */ if (in (i++, list)) { /* matching member found */ printf ("%d", i-1); /* print first member */ if (in (i, list)) { /* we have a range */ putchar ('-'); /* range seperator */ while (in (++i, list)); /* skip internal members */ printf ("%d", i-1); /* print last member */ } i++; /* avoid redundant check */ putchar (' '); } } } /*************************************************************************/ Now for the comparison: using small-model Lattice C, v 2.14, on a TI-PC, your routine compiled to a size of 0xCB bytes, mine 0xCC bytes. While I didn't gather execution times, an informal analysis indicates that both routines are a few assignments, comparisons, three calls to in (), and calls to putchar and printf. Since the number of calls made to putchar and printf are equl for both routines, they will be ignored. It appears that the bulk of the remaining execution time will involve the calls to in (). Therefore counting the number of calls to in () will give us a ballpark estimate of the execution time differences. For a 100 element set with the following members present [ 0 2 5-6 10-12 16-19 22-27 99 ] your routine called in () 104 times, mine 101. I call the two routines even in terms of size and execution speed. Beyond this, I think my version has some added benifits. My version can recognize member 0 of the set. I think my version is more intuitive; it models the process a human would follow when doing the same thing. And while I took advantage of the prefix/postfix ++ operators, the algorithm I followed is very general (it doesn't require multiple return statements or the ability to jump into a loop). Please don't confuse me with a structured programming purist. I have no problem using the goto in its many forms (i.e., at least single-entry, mulitiple-exit control constucts) when the situation requires it. Just remember that its use can cause problems for code optimizers, both human and machine. regards, Richard Hargrove CSNET: harged@ti-eg Texas Instruments, Inc. ARPA: harged%ti-eg@csnet-relay ----------------------- -------------------------------
mouse@mcgill-vision.UUCP (der Mouse) (04/21/86)
In article <69@brl-smoke.ARPA>, dmh@mit-borax.ARPA (David Harmon) writes: > [...] I need to print out all the elements of a set capable of containing > or not containing any value from 0..255. > [...] but I also wanted to contract adjacent members of a set into a range > syntax. > > /* Assume the existence of a type named "set", which is intended to simulate > the Pascal TYPE KeySet:SET OF 0..255; > Further assume the existence of a function > in(e,l); > set *l; > char e; > which returns a boolean 1 iff _e_ is an element of _*l_. > */ > [48-line example, using obscure goto, deleted] I once wrote some code which did something similar; adapting this to your problem.... As far as I can tell from your code (it's not the easiest thing in the world to understand), you want spaces instead of commas. For example, you want 1 3 5-10 not 1,3,5-10 I am also taking the liberty of producing a leading space, that is, this code produces " 1 3 5-10" instead of "1 3 5-10" This can be fixed with two more lines (a boolean variable and some code to use it). This is only 26 lines (saving of 22), and it is understandable (by comparison). Five more lines can be trimmed out if you are willing to sacrifice a smidgen of speed by calling in() more often than is really necessary: - delete the declarations of isin and oldin - delete the initialization of oldin - delete the oldin=isin assignment - change these three lines { isin = (i==MAX) ? 0 : in(listp,i); if (isin != oldin) { if (isin) to these two { if (((i==MAX)?0:in(listp,i)) != ((i==0)?0:in(listp,i-1))) { if ((i==MAX)?0:in(listp,i)) The messy `?:' operators in the last change above (and in the original assignment to isin) can be eliminated if in() is guaranteed to return 0 for out-of-bounds values of e. Just replace the entire `?:' expression with the call to in() contained in the `else' part. Without further ado, here is the code: #define MAX NUM_KEYWORDS /*The highest element in use by the application*/ wrtlist(listp) set *listp; { int i; int j; int isin; int oldin; oldin = 0; for (i=0;i<=MAX;i++) { isin = (i==MAX) ? 0 : in(listp,i); if (isin != oldin) { if (isin) { printf(" %d",i); j = i; } else { if (j < i-1) { printf("-%d",i-1); } } } oldin = isin; } } -- der Mouse USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse philabs!micomvax!musocs!mcgill-vision!mouse Europe: mcvax!decvax!utcsri!mcgill-vision!mouse mcvax!seismo!cmcl2!philabs!micomvax!musocs!mcgill-vision!mouse ARPAnet: utcsri!mcgill-vision!mouse@uw-beaver.arpa Wizard: One who can find and fix bugs in an emergency (such as during a site visit by funding agencies).
jso@edison (04/30/86)
In respose to the program by > Dave Harmon > dmh@mit-borax.arpa > dmh@borax.lcs.mit.edu where he asks for a way to avoid a goto in his loop (translated from Pascal). How about something like..... #include <stdio.h> #include "/usr/dmh/nastydefs" #define MAX NUM_KEYWORDS /*The highest element in use by the application*/ wrtlist (listp) set *listp; { unsigned char i; set list; list = *listp; for (i=0; i <= MAX; i++) { if (in(i,&list)) { unsigned char save_i; printf(" %d",i); save_i = i; while (++i <= MAX && in(i,&list)) ; if (i > save_i + 1) printf("-%d",i-1); /* doesn't matter that we'll i++ here, since we know !in(i,&list) */ } } printf("\n"); return(0); } [No guarantees, but you get the idea.] John Owens edison!jso%virginia@CSNet-Relay.ARPA General Electric Company Phone: (804) 978-5726 Factory Automation Products Division Compuserve: 76317,2354 houxm!burl!icase!uvacs ...!{ decvax!mcnc!ncsu!uvacs }!edison!jso gatech!allegra!uvacs