Xref: utzoo comp.lang.modula2:1231 comp.lang.c:15874 comp.lang.misc:2634 Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ncar!tank!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.modula2,comp.lang.c,comp.lang.misc Subject: Re: "for" loops Message-ID: <15692@mimsy.UUCP> Date: 29 Jan 89 18:00:46 GMT References: <19579@agate.BERKELEY.EDU> <8515@lanl.gov> Followup-To: comp.lang.misc Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 100 [followups redirected to comp.lang.misc] In article <8515@lanl.gov> jlg@lanl.gov (Jim Giles) writes: >[the floating point DO-loop construct] is considered a mistake because >the standard doesn't make any constraints on the accuracy of floating- >point arithmetic. So the trip count on a loop with floating-point >limits is not well-defined. (True in both C and FORTRAN.) >The C for-loop is even worse in this regard - the trip count is not >precomputed. That this is worse is mere opinion (or perhaps contentiousness). >Consider the following: > > for (x=0.0; x<=1.0, x+=0.1) {...} Or consider: tripcount = (int)((1.0-0.0)/0.1) + 1; /* or should this be rounded rather than truncated? */ /* (I have no F77 reference handy, sorry) */ for (x = 0.0; --tripcount >= 0; x += 0.1) ... which (in theory) does what the F77 construct DO label X = 0.0, 1.0, 0.1 does. But suppose the task is to find the accumulated error? for (i = 0, x = 0.0; x <= 1.0; i++, x += 0.1) /* void */; printf("[0.0,1.0] count took %d steps; x-1.0=%g\n", i, x - 1.0); which in F77 can be written (I will use `WHILE' here for conciseness and to avoid those blasted statement numbers) X = 0.0 I = 0 WHILE (X .LE. 1.0) DO X = X + 0.1 I = I + 1 ENDWHILE ! (I forget whether PRINT * puts spaces around numbers) PRINT *, '[0.0,1.0] count took', I, 'steps; x-1.0=', X-1.0 Not really that different after all (although the FORTRAN version is in ugly uppercase :-) ). >The value of x for each trip through the loop is a sum of 0.1+ ... +0.1, >a value which suffers round-off or truncation on each successive add. >If the four operations in the computation of the Fortran trip count >lead to ambiguous results, the 11 adds in the above are even worse. Any programmer worth his pay is aware of the method by which the trip count is determined, and will write the appropriate code in the appropriate situation. It is true that situations demanding floating point loop counters are rare. In any case, the generalised `for' loop construct in C is very worthwhile, although a specialised precomputed-count loop construct (a la most other Algol/FORTRANnish languages) might be nice. C's `for' fits a number of situations well, such as for (p = head; p != NULL; p = p->next) for simple list traversal, or for (p = head.next; p != &head; p = p->next) for circular queues, or for (x = init; fn1(x) < fn2(x); x = fn3(x)) for essentially arbitrary stepping around a graph of two functions looking for a crossover. For loops with a fixed iteration limit, a construct like for i in [1..N) do is often better, since it is clearer and allows the compiler to use shadowing or downcounts or whatnot without requiring it to determine that the limit is in fact fixed. It is sometimes worthwhile in C to recode something like for (i = 1; i < f(); i++) /* where f() is a pure function */ as for (j = f(), i = 1; --j > 0; i++) or (clearer but sometimes slower) for (i = 1, j = f(); i < j; i++) and this sort of nonsense is really best left to the compiler. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris