[comp.lang.c] "for" loops

abcscagz@csuna.UUCP (stepanek/cs assoc) (01/26/89)

In article <739@jupiter.iis.UUCP> heiser@iis.ethz.ch (Gernot Heiser) writes:
>
>worst features. C's 'for' is really a 'while' with an initialization clause and
>a designated spot that may contain an incrementation clause. What I consider a
>"real" 'for' (as opposed to the while/repeat/loop family) is a construct that
>executes a specific number ot times, the iteration count being determined
>BEFORE the processing of the body starts. This is what is really needed most of
>the time in numerical programs. The other cases are exactly what while/repeat/
>loop constructs are for.


Actually, C's "for" can be duplicated EXACTLY by C's "do ... while" loops.
Consider:

    for (i = 0; i <= 17; ++i)
    {
        stuff();
        more_stuff();
    }

versus:

    i = 0;
    do {
        stuff();
        more_stuff();
    } while (++i <= 17);


These two iterations are indistinguishable from one another.  The "for" term
in C is totally superfluous and is only included because it makes it look like
languages that have a more "for"-ish "for" statement, like Pascal or Modula.
(I won't even get into Algol's "for" here....)

-- 
Jeff Boeing:  ...!csun.edu!csuna!abcscagz    (formerly tracer@stb.UUCP)
--------------------------------------------------------------------------
"When Polly's in trouble I am not slow  /  It's hip, hip, hip and away I go!"
                            -- Underdog

hascall@atanasoff.cs.iastate.edu (John Hascall) (01/27/89)

In article <739@jupiter.iis.UUCP> heiser@iis.ethz.ch (Gernot Heiser) writes:

>worst features. C's 'for' is really a 'while' with an initialization clause and
>a designated spot that may contain an incrementation clause. What I consider a
>"real" 'for' (as opposed to the while/repeat/loop family) is a construct that
>executes a specific number ot times, the iteration count being determined
>BEFORE the processing of the body starts. This is what is really needed most of
 ^^^^^^

  I can't count the number of times this has nailed C novices who have had
  experience with other languages (i.e., FORTRAN).
  For example:

      for ( i=0; i < fn_with_side_effects(x); i++ ) {
	  blue_dog_moon_up();
      }

>the time in numerical programs. The other cases are exactly what while/repeat/
>loop constructs are for.

    As far as I can see, the main purpose of C's "for" is to save space,
    which is one of C's strengths (to some, probably not to MIS/COBOL
    types [oh! sorry, this isn't the misc.jobs.misc C/COBOL-CS/MIS
    flamewar?])

    John Hascall
    ISU Comp Center

bowles@eris.berkeley.edu (Jeff A. Bowles) (01/28/89)

In article <738@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu (John Hascall) writes:
>In article <739@jupiter.iis.UUCP> heiser@iis.ethz.ch (Gernot Heiser) writes:
>
>>worst features. C's 'for' is really a 'while' with an initialization clause and
>>a designated spot that may contain an incrementation clause. What I consider a
>>"real" 'for' (as opposed to the while/repeat/loop family) is a construct that
>>executes a specific number ot times, the iteration count being determined
>>BEFORE the processing of the body starts....

I hate to fan flames like this, but I can't resist. I have strong reservations
about certain things in C, but the "for" loop is something that's really
kinda nice:

1. It's not restrictive on the types of the indices, because it defines a
   more general construct. If I had a nickel for every time, in Fortran,
   that I needed a loop that ran from 0.0 to 1.0 by 0.1 (or the like) and
   had to use INTEGER to do it. Or Pascal, which lacked the "step" clause
   so that you couldn't increment by more than what the language-designer
   wanted.
2. Yes, you're right, it's redundant - the "while (expr) statement;" and
   the "do statement; while (expr)" and the "for (expr;expr;expr) statement;"
   have a lot of redundancy, probably for brevity. So?
3. Because it's not restrictive on the types, and because I don't have to
   know EXACTLY how many times it will run through the body, I can do things
   like:
	for (p = headoflist; p != NULL; p = p->l_next)
		process(p);
   The article said that you could code loops that run a arbitrary
   number of times, using something like:
	for (i = 0; i < thingwithsideeffects(i); i++)
		munge();
   And while the author of the article is correct, you can code garbage
   like this in most languages. Fault the coder, in this case.

The only thing I really miss is something you Unix-types will recognize
from awk (and perhaps from Algol 68?) -
	for (t in table)
		process(table[t]);
But that's another story....

	Jeff Bowles

ags@s.cc.purdue.edu (Dave Seaman) (01/28/89)

In article <19579@agate.BERKELEY.EDU> bowles@eris.berkeley.edu (Jeff A. Bowles) writes:
>   If I had a nickel for every time, in Fortran,
>   that I needed a loop that ran from 0.0 to 1.0 by 0.1 (or the like) and
>   had to use INTEGER to do it. 

Fortran does not require an integer.  The control variable of a DO loop may
be integer, real, or double precision.  It is perfectly legal to write:

	REAL X
	. . .
	DO 10 X=0.0, 1.0, 0.1
	. . .

according to the current standard, but this has been recognized as a
mistake which will probably be rectified in the next standard.  You can't
even tell how many iterations you will get from the DO statement above
(10? 11? how do you know?).  Why anyone would want to add this deficiency
to a language that doesn't currently have broken FOR statements is beyond
me.

-- 
Dave Seaman	  					
ags@j.cc.purdue.edu

arrom@aplcen.apl.jhu.edu (Ken Arromdee) (01/28/89)

>Actually, C's "for" can be duplicated EXACTLY by C's "do ... while" loops.

I suspect you're going to get an awful lot of flames for saying this.  What
about
	for(i=0; i<=j; i++)
		printf("%d\n",i);
Since a do-while loop has the test condition at the termination of the loop,
it is not possible to produce an equivalent do-while version, for the
behavior will differ if j is less than 0.
--
               EARTH                  --Kenneth Arromdee
           smog  |   bricks          UUCP: ....!jhunix!ins_akaa
        AIR     mud       FIRE   INTERNET: arromdee@crabcake.cs.jhu.edu
      soda water |   tequila       BITNET: g49i0188@jhuvm
               WATER           (please, no mail to arrom@aplcen)

jlg@lanl.gov (Jim Giles) (01/28/89)

From article <19579@agate.BERKELEY.EDU>, by bowles@eris.berkeley.edu (Jeff A. Bowles):
> [...] 
> 1. It's not restrictive on the types of the indices, because it defines a
>    more general construct. If I had a nickel for every time, in Fortran,
>    that I needed a loop that ran from 0.0 to 1.0 by 0.1 (or the like) and
>    had to use INTEGER to do it. Or Pascal, which lacked the "step" clause
>    so that you couldn't increment by more than what the language-designer
>    wanted.
> [...] 
> 	Jeff Bowles

ALL standard conforming Fortran processors allow the following:

      DO 10 i=0.0,1.0,0.1

The standard committee now considers this to be a mistake and is likely
to remove it in 8x, but for the moment this is a standard feature.

It 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.
The C for-loop is even worse in this regard - the trip count is not
precomputed.  Consider the following:

      for (x=0.0; x<=1.0, x+=0.1) {...}

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.
For a loop from 0.0 to 1000.0 by 0.01 on a 32-bit floating-point machine,
the round-off of the last 100 adds is comparable to the increment itself!
This may be another reason for the undesireable feature in C of assuming
double precision as the default floating-point.

J. Giles

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

In article <1611@csuna.UUCP> abcscagz@csuna.csun.edu (Jeff Boeing) writes:
>Actually, C's "for" can be duplicated EXACTLY by C's "do ... while" loops.

Only in the sense that, given "if" and any looping construct, any
of the other looping constructs can be simulated.  But there is no
obvious straightforward mapping of a general "for" onto "do...while".
For one thing, a "for" need not execute the controlled statement at
all whereas "do...while" always executes it at least once.

The other thing to beware of is the behavior of "continue".  Many
programmers have been confused by trying to map "for" into "while"
and not realizing that "continue" does different things in the two
cases.

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

In article <19579@agate.BERKELEY.EDU> bowles@eris.berkeley.edu (Jeff A. Bowles) writes:
>... the "for" loop is something that's really kinda nice:

The main purpose of "for" in C is to collect all the loop control
pieces together on a single line to make them more evident:

	for ( p = head.next; p != &head; p = p->next )
		...

Certainly this particular can be accomplished in numerous ways,
but it's hard to imagine anything that would be clearer than that.

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

In article <8515@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>      for (x=0.0; x<=1.0, x+=0.1) {...}
>For a loop from 0.0 to 1000.0 by 0.01 on a 32-bit floating-point machine,
>the round-off of the last 100 adds is comparable to the increment itself!
>This may be another reason for the undesireable feature in C of assuming
>double precision as the default floating-point.

No, I don't think so.  I've never known anyone to recommend a loop
like the above.  The reasons for defaulting floating-point computations
to double precision in original C (no longer required in ANSI C) were
that it was easier to support on the PDP-11 that way and that numerical
applications were so rare in the UNIX C environment that the potential
loss of speed for such applications was not considered significant.

crew@Polya.Stanford.EDU (Roger Crew) (01/28/89)

Here's a quiz:
How would you write the following in C?

	VAR a, b, c : Char;
	...
	FOR c = a TO b DO ... END;

You can even assume that the body of the loop affects neither a nor b.
Hint:  the answer is *not*

	char a, b, c;
	...
	for (c = a; c <= b; ++c) { ... }

(just try a = 0 and b = 255 in the case of 8 bit chars).
--
Roger Crew		Copyright 1989 -- All Rights Reserved.   (so there!)
Usenet:    {arpa gateways, decwrl, uunet, rutgers}!polya.stanford.edu!crew
Internet:  crew@polya.Stanford.EDU	

guy@auspex.UUCP (Guy Harris) (01/28/89)

>Actually, C's "for" can be duplicated EXACTLY by C's "do ... while"
>loops.

No, they can't.

	for (i = 0; i < N; i++)	/* N is a *variable* here */
		stuff;

isn't duplicated by

	i = 0;
	do
		stuff;
	while (++i < N);

because, if N is 0, the first loop will be executed 0 times and the
second loop will be executed 1 time.  It *is* duplicated by

	i = 0;
	while (i < N) {
		stuff;
		i++;
	}

as long as "stuff" doesn't include a "continue" (see p. 60 of K&R
Second Edition; there's probably similar stuff somewhere in the First
Edition).

>These two iterations are indistinguishable from one another.  The "for" term
>in C is totally superfluous and is only included because it makes it look like
>languages that have a more "for"-ish "for" statement, like Pascal or Modula.

Well, to quote something else from p. 60:

	   The "for" is preferable when there is a simple initialization
	since it keeps the loop control statements close together and
	visible at the top of the loop.

Whether you agree with that opinion or not is your business; however, it
seems the reason "for" was included wasn't solely to "make it look like
languages that have a more 'for'-ish 'for' statement", but because DMR
felt the "for" statement had merits of its own.

Devin_E_Ben-Hur@cup.portal.com (01/29/89)

Jeff Boeing writes:
> Actually, C's "for" can be duplicated EXACTLY by C's "do ... while" loops.
> Consider:
> 
>     for (i = 0; i <= 17; ++i)
>     {
>         stuff();
>         more_stuff();
>     }
> 
> versus:
> 
>     i = 0;
>     do {
>         stuff();
>         more_stuff();
>     } while (++i <= 17);
> 
> 
> These two iterations are indistinguishable from one another.  The "for" term
> in C is totally superfluous and is only included because it makes it look
> languages that have a more "for"-ish "for" statement, like Pascal or Modula.

Nope.  This is the actual equivalent code:

	i = 0;
	while (i <= 17) {
		stuff();
		more_stuff();
continue_here:
		++i;
	}

The for loop tests at the first iteration, and a continue statement will
branch to the increment not to the test.

The C for statement is a convenience allowing the programmer to place
all loop control statements in one place instead of spreading them all
over the loop.  I've always thought the limits placed on Pascal & Modula's
for statements were silly, but that's just MHO.

Devin_Ben-Hur@cup.portal.com
...!ucbvax!sun!cup.portal.com!devin_e_ben-hur

abcscagz@csuna.UUCP (stepanek/cs assoc) (01/29/89)

Hoo boy, did I ever mess up in my last posting.
I forgot that a C "for" loop may be executed zero times.
So, let me rephrase my conviction that a C "for" loop is superfluous
because it can be replaced by an equivalent "while" loop, NOT an
equivalent "do ... while" loop:

    for (i = 0; i <= 17; i = sqr(i) + 2)
       <stuff>;

versus:

    i = 0;
    while (i <= 17)
    {
        <stuff>;
        i = sqr(i) + 2;
    }

There.  I hope I have redeemed myself in the face of my previous blasphemy.

And now that I think about it, it IS nice to have final incrementational
conditions in the loop declaration rather than at the end of the loop-body,
as the "while" case forces you to do.
   (Although I do still believe that the initial "statement" field of a
"for" loop is superfluous.)

-- 
Jeff Boeing:  ...!csun.edu!csuna!abcscagz    (formerly tracer@stb.UUCP)
--------------------------------------------------------------------------
"When Polly's in trouble I am not slow  /  It's hup, hup, hup and awaay I go!"
                            -- Underdog

jlg@lanl.gov (Jim Giles) (01/29/89)

From article <9527@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn ):
> In article <8515@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>>      for (x=0.0; x<=1.0, x+=0.1) {...}
>>For a loop from 0.0 to 1000.0 by 0.01 on a 32-bit floating-point machine,
>>the round-off of the last 100 adds is comparable to the increment itself!
>> [...]
> 
> No, I don't think so.  I've never known anyone to recommend a loop
> like the above.  [...]

I know of at least one person who recommended such a loop - the person
I was originally responding to.  He felt that the above loop was a
clear advantage over what Fortran DO loops could do.  He was wrong
on both counts (Fortran CAN do it and it's not an improvement).

J. Giles

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

[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

schmidt@blanche.ics.uci.edu (Doug Schmidt) (01/30/89)

In article <1626@csuna.UUCP> abcscagz@csuna.csun.edu (Jeff Boeing) writes:
++Hoo boy, did I ever mess up in my last posting.
++I forgot that a C "for" loop may be executed zero times.
++So, let me rephrase my conviction that a C "for" loop is superfluous
++because it can be replaced by an equivalent "while" loop, NOT an
++equivalent "do ... while" loop:

I don't think you've gone far enough.  After all, can't both a while
loop and a for loop be replaced by an if statement and a goto?

++
++    for (i = 0; i <= 17; i = sqr(i) + 2)
++       <stuff>;
++

versus

   i = 0;        
LOOP_HEAD:
   if (i <= 17) {
      <stuff>
      i = sqr(i) + 2;
      goto LOOP_HEAD;
   }
   
In fact, aren't all high-level control constructs superfluous?

Doug

p.s.  ;-) ......
--
schmidt@ics.uci.edu (ARPA) |   Per me si va nella citta' dolente.
office: (714) 856-4043     |   Per me si va nell'eterno dolore.
                           |   Per me si va tra la perduta gente.
                           |   Lasciate ogni speranza o voi ch'entrate.

bill@twwells.uucp (T. William Wells) (01/30/89)

In article <1626@csuna.UUCP> abcscagz@csuna.csun.edu (Jeff Boeing) writes:
: Hoo boy, did I ever mess up in my last posting.
: I forgot that a C "for" loop may be executed zero times.
: So, let me rephrase my conviction that a C "for" loop is superfluous
: because it can be replaced by an equivalent "while" loop, NOT an
: equivalent "do ... while" loop:

C is superfluous because it can be replaced by an equivalent assembly
program.

---

The C for loop exists because it encapsulates the common initialize,
test, and update control structure; it does not exist because such
encapsulation can't be written any other way, or to save keystrokes,
or any other such irrelevant reason.

---
Bill
{ uunet!proxftl | novavax } !twwells!bill

diamond@csl.sony.JUNET (Norman Diamond) (01/30/89)

In article <19579@agate.BERKELEY.EDU>, bowles@eris.berkeley.edu (Jeff A. Bowles) writes:

[Praising C's for-loop over other languages' iterators]

>    If I had a nickel for every time, in Fortran,
>    that I needed a loop that ran from 0.0 to 1.0 by 0.1 (or the like) and
>    had to use INTEGER to do it.

If you do such iterations in floating-point, adding 0.1 each time
instead of multiplying an integer by 0.1, you will lose a lot of
nickels.  I wouldn't mind receiving them.  (The Vancouver Stock
Exchange did that kind of thing.  Eventually their computed index
of stock prices became about half of the correct value, and they
finally noticed they had a bug.)

>    Or Pascal, which lacked the "step" clause
>    so that you couldn't increment by more than what the language-designer
>    wanted.

This was not due to what the language designer wanted.  Remember that
he only had resources available for a small compiler and had to provide
maximal assistance to novice students in error checking.  Testing "for"
statements for overflow when the stepsize is not 1 is more difficult.
Now if you had complained that the modern version, i.e. the draft ISO
Extended Pascal standard, still doesn't allow it, then I would agree
with your complaint.

> The only thing I really miss is something you Unix-types will recognize
> from awk (and perhaps from Algol 68?) -
> 	for (t in table)
> 		process(table[t]);
> But that's another story....

Do you mean:  for (t in some_set) process (table[t]) ?
At least the draft Extended Pascal standard has this one.
-- 
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

john@frog.UUCP (John Woods) (01/30/89)

In article <19579@agate.BERKELEY.EDU>, bowles@eris.berkeley.edu (Jeff A. Bowles) writes:
>    If I had a nickel for every time, in Fortran,
>    that I needed a loop that ran from 0.0 to 1.0 by 0.1 (or the like)
...you'd be broke.  You NEVER need a loop that runs from 0.0 to 1.0 by 0.1.
1/10 is a repeating fraction in binary, and thus .1+.1+.1+.1+.1+.1+.1+.1+.1+.1
does NOT equal 1.0.  Read "The Elements of Programming Style" for more tidbits
on this and other programming topics.
-- 
John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101
...!decvax!frog!john, john@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu

Presumably this means that it is vital to get the wrong answers quickly.
		Kernighan and Plauger, The Elements of Programming Style

fransvo@htsa.uucp (Frans van Otten) (01/30/89)

In article <6224@paris.ics.uci.edu> Doug Schmidt <schmidt@blanche.ics.uci.edu> writes:
>I don't think you've gone far enough.  After all, can't both a while
>loop and a for loop be replaced by an if statement and a goto?
>[..]
>In fact, aren't all high-level control constructs superfluous?
>
>Doug

And I propose to change the name of this newsgroup. It should
be comp.lang.not_modula2_but_c !

-- 
                         Frans van Otten
                         Algemene Hogeschool Amsterdam
			 Technische en Maritieme Faculteit
                         fransvo@htsa.uucp

dg@lakart.UUCP (David Goodenough) (01/31/89)

From article <1611@csuna.UUCP>, by abcscagz@csuna.UUCP (stepanek/cs assoc):
> Actually, C's "for" can be duplicated EXACTLY by C's "do ... while" loops.
> Consider:
> 
>     for (i = 0; i <= 17; ++i)
>     {
>         stuff();
>         more_stuff();
>     }
> 
> versus:
> 
>     i = 0;
>     do {
>         stuff();
>         more_stuff();
>     } while (++i <= 17);

Yes, but how about:

	for (i = 0; i <= a; i++)
	 {
	    lots_of_stuff();
	 }

against:

	i = 0;
	do
	 {
	    lots_of_stuff();
	 } while (++i <= a);

when the value of a is (say) -5. Are you _SURE_ these two are the same?

Better would be to say a for loop can be replaced by a while loop:

	i = 0;
	while (i <= a /* or 17 */)
	 {
	    lots_of_stuff();
	    i++;
	 }
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

barmar@think.COM (Barry Margolin) (01/31/89)

In article <1381@X.UUCP> john@frog.UUCP (John Woods) writes:
]In article <19579@agate.BERKELEY.EDU>, bowles@eris.berkeley.edu (Jeff A. Bowles) writes:
]>    If I had a nickel for every time, in Fortran,
]>    that I needed a loop that ran from 0.0 to 1.0 by 0.1 (or the like)
]...you'd be broke.  You NEVER need a loop that runs from 0.0 to 1.0 by 0.1.
]1/10 is a repeating fraction in binary

Just because Fortran can't do it doesn't mean that he doesn't NEED it;
it just means he can't GET it.  Since the real world mostly works in
decimal, I imagine that the need is frequent.  Luckily, there are
well-known and easy ways around this problem.


Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

marti@ethz.UUCP (Robert Marti) (01/31/89)

Please stop cross-posting this drivel about for-loops in C to
comp.lang.modula2!  (Gernot, are you listening, too?)  Those
Modula-2 hackers who don't know that a for-loop in C can be
expressed as a while-loop but not as a do-loop probably couldn't
care less ...

-- 
Robert Marti                    Phone:       +41 1 256 52 36
Institut fur Informatik
ETH Zentrum                     CSNET/ARPA:  marti%ifi.ethz.ch@relay.cs.net
CH-8092 Zurich, Switzerland     UUCP:        ...uunet!mcvax!ethz!marti

flint@gistdev.UUCP (02/01/89)

I've always felt that it should be the job of programming languages to let
me say what I want to do concisely, and then they should do it the way I
want.  Therefore, there is no reason I can see that the language should not
let you have an increment of .1, since it is quite clear exactly what I
want it to do in this case: the compiler ought to be able to see (easily)
that it needs to set up a dummy integer counter to actually control the
loop, and divide by 10 at the top of the loop for you to give you the index
you use.  By doing so, it allows experienced people to do less typing, and
protects beginners from their ignorance- you win both ways.  (It cannot
necessarily deal with the round-off problems at the end of the loop of
course: in the example cited, the question was whether to run the loop for
10 or 11 iterations.  However, if the compiler does one division to make
that decision & then codes an integer loop for you it's much more likely
it will be what you wanted.)

Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
INTERNET: flint%gistdev@uxc.cso.uiuc.edu
UUCP:     {uunet,pur-ee,convex}!uiucuxc!gistdev!flint

hascall@atanasoff.cs.iastate.edu (John Hascall) (02/03/89)

In article <7800002@gistdev> flint@gistdev.UUCP writes:

>  ...  Therefore, there is no reason I can see that the language should not
>let you have an increment of .1, since it is quite clear exactly what I
>want it to do in this case: the compiler ought to be able to see (easily)
>that it needs to set up a dummy integer counter to actually control the
>loop, and divide by 10 at the top of the loop for you to give you the index
 
 How's it supposed to know to use 10? 
 When I do 1.0/0.1, I get 9.99999985...  Well, it's pretty close to 10,
 let's use that :-)

>    ... in the example cited, the question was whether to run the loop for
>10 or 11 iterations.  However, if the compiler does one division to make
>that decision & then codes an integer loop for you it's much more likely
>it will be what you wanted.)

  That's the whole problem with this!  I don't want code that's LIKELY
  to be what I wanted... I want the damn thing to do what I asked for.

  What's so hard about writing:

       for (i=0; i<10; i++) {
           f = 0.1*i;
	   /* etc */
       }

  John Hascall
  ISU Comp Center

bph@buengc.BU.EDU (Blair P. Houghton) (02/03/89)

In article <7800002@gistdev> flint@gistdev.UUCP writes:
>
>I've always felt that it should be the job of programming languages to let
>me say what I want to do concisely, and then they should do it the way I
>want.

From the DEC Ultrix fortune-cookie file:

	"When someone says 'I want a programming language in which I
	need only say what I wish done,' give him a lollipop."

So, would you like grape or lime?

				--Blair
				  "I always like to do the right thing..."

geoff@warwick.UUCP (Geoff Rimmer) (02/03/89)

In article <6419@polya.Stanford.EDU> crew@Polya.Stanford.EDU (Roger Crew) writes:
>Here's a quiz:
>How would you write the following in C?
>
>	VAR a, b, c : Char;
>	...
>	FOR c = a TO b DO ... END;
>
>You can even assume that the body of the loop affects neither a nor b.
>Hint:  the answer is *not*
>
>	char a, b, c;
>	...
>	for (c = a; c <= b; ++c) { ... }
>
>(just try a = 0 and b = 255 in the case of 8 bit chars).
>--

What a stupid question.  If you are going to count from 0 to 255, you
wouldn't use char in the first place - you'd use unsigned char, or
int.  I can't see what you're getting at, at all.

Go back to writing Fortran.  Let the *real* programmers use C. :-)

>Roger Crew		Copyright 1989 -- All Rights Reserved.   (so there!)
>Usenet:    {arpa gateways, decwrl, uunet, rutgers}!polya.stanford.edu!crew
>Internet:  crew@polya.Stanford.EDU	

	------------------------------------------------------------
	Geoff Rimmer, Computer Science, Warwick University, England.
			geoff@uk.ac.warwick.emerald

	"I didn't ask to be made.  No consulted me or considered my
	 feelings in the matter, not that anyone considered that I
	 might *have* feelings.  After I was made, I was left in a
	 dark room for six months, and me with this terrible pain in
	 all the diodes down my left side.  My one and only true
	 friend was a small rat.  One day it climbed into a cavity of
	 my inner leg and died.  I've a horrible feeling it's still
	 there." - Marvin, The Hitch Hiker's Guide to the Galaxy.

	------------------------------------------------------------

sbigham@dukeac.UUCP (Scott Bigham) (02/03/89)

In article <7800002@gistdev> flint@gistdev.UUCP writes:
>
>I've always felt that it should be the job of programming languages to let
>me say what I want to do concisely, and then they should do it the way I
>want.

What you want, it seems, is a programming language that can read your mind.

>       Therefore, there is no reason I can see that the language should not
>let you have an increment of .1, since it is quite clear exactly what I
>want it to do in this case: 

Obvious to you.  How do you explain it to the compiler?

>			     the compiler ought to be able to see (easily)
>that it needs to set up a dummy integer counter to actually control the
>loop, and divide by 10 at the top of the loop for you to give you the index
>you use.

That's not at all obvious, and in many cases it's not even possible.  How do
you resolve this loop?

 for (i=0.0;i<100.0;i+=PI);

In the general case, such optimizations as you describe would require lots of
convolutions and aren't useful often enough to be worth it.  If you really
want the compiler to use an integer, tell it to.

>	   By doing so, it allows experienced people to do less typing, and
>protects beginners from their ignorance- you win both ways.

Not necessarily what we want to do.  If you shelter beginners from their
mistakes, they can't learn from them.

Remember: for every situation in which the compiler does exactly what you 
want, there are at least ten people who think the compiler should do it
differently.

>Flint Pellett, Global Information Systems Technology, Inc.
>1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
>INTERNET: flint%gistdev@uxc.cso.uiuc.edu
>UUCP:     {uunet,pur-ee,convex}!uiucuxc!gistdev!flint

						sbigham
-- 
Scott Bigham                         "The opinions expressed above are
Internet sbigham@dukeac.ac.duke.edu   (c) 1989 Hacker Ltd. and cannot be
USENET   sbigham@dukeac.UUCP          copied or distributed without a
...!mcnc!ecsgate!dukeac!sbigham       Darn Good Reason."

flint@gistdev.UUCP (02/04/89)

/* Written 10:02 am  Feb  2, 1989 by atanasoff.cs.iastate.edu!hascall in gistdev:comp.lang.c */
In article <7800002@gistdev> flint@gistdev.UUCP writes:

 How's it supposed to know to use 10? 
 When I do 1.0/0.1, I get 9.99999985...  Well, it's pretty close to 10,
 let's use that :-)

I guess it is obvious to me, not to others: If the increment that the user
wrote was 0.1, with one digit to the right of the decimal point, the
compiler should obviously use 10 as the denominator because 0.1 = 1/10.  If
the user wrote a loop that incremented by 0.127, the compiler writer should
use 1000 for the divisor, because the user had 3 digits to the right of the
decimal.   Any increment the user can type into their program can be exactly
represented as a fraction unless the compiler is stupid enough to throw
the information away.  (IE, they use PI for the increment: where did you
get PI?  Someplace had a #define  PI 3.1415926.  If the user gave you
7 digits of precision, use 10 ** 7 as the divisor that gives the floating
point value you need.)

It should be noted that I advocated doing this to "simple" loops where it
works, not to every loop.  In the
    do 10 i=0,1,0.1
case, you can KNOW to run this loop exactly 11 times: but not if you stupidly
try to divide 1/0.1 with binary based arithmetic, where it might round to a
result less than 10.  Your user wrote the loop in decimal, and in decimal the
arithmetic produces an exact result.  Think the math is too complex a task
for your compiler to do?  Then try this simple trick:
What the programmer wrote in their code:             do  10 i=2.5,3.75,0.25
Move the decimal points in the text 2 places right:  do  10 i=250,375,25
(Manipulate the text string if you feel the need.)
Bingo, you've got an integer loop, you know to get the floating loop
index you divide by (10 ** 2) or 100 (because you slid the decimal places
2 positions in order to get rid of all the digits right of the decimal
points.)  Note that in some loops, where i isn't even used in the body of
the loop, you can dispense with the floating point altogether now.

You can certainly argue that doing the above won't protect you in every
single case, and you're right, it won't.  But that sounds to me a lot like
arguing that you shouldn't have optimizers because they might change the
code to not be exactly what the programmer wrote.  I believe that in all
the examples presented so far you do know exactly what the programmer wanted
you to do.

Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
INTERNET: flint%gistdev@uxc.cso.uiuc.edu
UUCP:     {uunet,pur-ee,convex}!uiucuxc!gistdev!flint

hascall@atanasoff.cs.iastate.edu (John Hascall) (02/06/89)

In article <7800003@gistdev> flint@gistdev.UUCP writes:


>It should be noted that I advocated doing this to "simple" loops where it
>works, not to every loop.  In the
>    do 10 i=0,1,0.1
>case, you can KNOW to run this loop exactly 11 times: but not if you stupidly
>try to divide 1/0.1 with binary based arithmetic, where it might round to a
>result less than 10.  Your user wrote the loop in decimal, and in decimal the
>arithmetic produces an exact result.  Think the math is too complex a task
>for your compiler to do?  Then try this simple trick:
>What the programmer wrote in their code:             do  10 i=2.5,3.75,0.25
>Move the decimal points in the text 2 places right:  do  10 i=250,375,25
>(Manipulate the text string if you feel the need.)
>Bingo, you've got an integer loop, you know to get the floating loop
>index you divide by (10 ** 2) or 100 (because you slid the decimal places
>2 positions in order to get rid of all the digits right of the decimal
>points.)  

   Sure, it works in some simple cases, but how do you propose to
   handle:

        start = expression-which-gives_2.5
	end = expression-which-gives_3.75
	incr = expression-which-gives_0.25
	do 10 i=start,end,incr

    now we don't know which power of 10 to use, having no "textual"
    information from the users program.

    Or how about:

       do i=0.0, 4.0, 2.0/3.0

    I suppose now our compiler has to do fractions too...because to
    you and I the meaning is clear, but to a compiler it's:

       do i=0.0, 4.0, 0.6666667

    giving the sequence:               instead of the expected:

       0.0000000                          0.0000000
       0.6666667                          0.6666667
       1.3333334                          1.3333333
       2.0000001                          2.0000000
       2.6666668                          2.6666667
       3.3333335                          3.3333333
       ---------                          4.0000000
       4.0000002                          ---------
					  4.3333333


      I don't know who said it, but, "If you make a system fool-proof, only
   a fool will use it"

   John Hascall
   ISU Comp Center

   p.s. liberally apply :-)'s above, I just like to disagree, it provokes
        thought.

crew@Polya.Stanford.EDU (Roger Crew) (02/07/89)

In article <1004@ubu.warwick.UUCP>, geoff@warwick (Geoff Rimmer) writes:
> In article <6419@polya.Stanford.EDU> crew@Polya.Stanford.EDU (Roger Crew) writes:
> >Here's a quiz:
> >How would you write the following in C?
> >
> >	VAR a, b, c : Char;
> >	...
> >	FOR c = a TO b DO ... END;
> >
     [ ... yup, this discussion ...]
>
> What a stupid question.  If you are going to count from 0 to 255, you
> wouldn't use char in the first place - you'd use unsigned char, or
> int.  I can't see what you're getting at, at all.

I'll grant that, for the benefit of compilers that *have* signed
chars, I actually did intend to say ``unsigned char'' rather than
``char''.  The fact of the matter is, however, that

        unsigned char a;
	for( c=0; c<=255; ++c) {...}

still doesn't work.  You can try it if you like, or you can read the
submissions from the other 10 posters who understand what's going on...  

The fact that I was using chars signed or unsigned is irrelevant to
the point I was trying to make, namely that the semantics of C
for-loops and Modula/Pascal for-loops are entirely different -- it is
not simply a case of one being more general than the other.  While
it's fairly obvious that a general C for-loop often can't be written
as a Modula for-loop, it's not so obvious (or at least, *I* didn't think
it was completely obvious...) that to do a general Modula for-loop
in C *also* requires strange contortions.

As for *why* I'd want to be counting with chars, just consider any
application requiring some kind of array indexed by chars, e.g.,

	VAR font : ARRAY Char OF Bitmap;

It's an obvious thing to do in Modula.  I suppose this also
illustrates the danger of carrying over one languages way of thinking
into another, a problem that does not confine itself to for-loops.

> Go back to writing Fortran.  Let the *real* programmers use C. :-)

I'll let this statement speak for itself.  :=)

--
Roger Crew					``Beam Wesley into the sun!''
Usenet:    {arpa gateways, decwrl, uunet, rutgers}!polya.stanford.edu!crew
Internet:  crew@polya.Stanford.EDU

flint@gistdev.UUCP (02/07/89)

/* Written 12:19 pm  Feb  5, 1989 by atanasoff.cs.iastate.edu!hascall in gistdev:comp.lang.c */

>   Sure, it works in some simple cases, but how do you propose to
>   handle:
>
>        start = expression-which-gives_2.5
>	end = expression-which-gives_3.75
>	incr = expression-which-gives_0.25
>	do 10 i=start,end,incr
>
>    now we don't know which power of 10 to use, having no "textual"
>    information from the users program.

From my previous posting: (as George Bush would say: "Read my lips" :-) )
>>It should be noted that I advocated doing this to "simple" loops where it
>>works, not to every loop.  

I believe we both just said the same thing, so I'll assume you are agreeing
with me: you just provided an example of a case you can't optimize as I
stated there would be.


>    Or how about:
>
>       do i=0.0, 4.0, 2.0/3.0
>
>    I suppose now our compiler has to do fractions too...because to
>    you and I the meaning is clear, but to a compiler it's:
>
>       do i=0.0, 4.0, 0.6666667
 
The compiler has two choices here:  1. Do the division right away, as you
just did (something I believe is an error: to use your arguments, "if I wanted
0.666667 instead of 2/3, I would have said 0.66667!"), or 2. be smart, and
multiply the denominators through: this is exactly what it is doing in the
case of decimals.  ie, (so that it is obvious :-) ), this loop:
(Why are we debating this using Fortran syntax for God's sake?)
    do  i = 3.25,4.1,.1
is really the same (when written in terms of fractions) as this one:
    do  i = 325./100.,41./10.,1./10.
and when you multiply everything by 100 and it becomes integer, ie:
   do   i = 325,410,10

So if your user had written (hascall's previous example below)
>       do i=0.0, 4.0, 2.0/3.0
you just multiply everything by 3 to convert it into this:
        do i=0,12,2
        float=i/3.0
And if they wrote this:
        do i=2./3.,15./4.,1./12.
You can multiply each by 12 to get this loop:
	do i=8,45,1
	float=i/12.0

(How to decide what the smallest integer value to multiply through by is left
as a 7th grade level arithmetic exercise for the reader.)

In other words, I was already advocating that the compiler do fractions,
you assumed that I only wanted it to deal with the specific case where
the denominators in the fractions are powers of 10.  If the user writes
2/3 in their code instead of 0.667, and the compiler can make use of the
extra information that 2/3 conveys, then it ought to do so.

I don't think (but I could be wrong: it has happened before :-) ) that
there is any loop you can write that contains only constants for the
loop start/end/increment that cannot be converted into an integer
controlled loop in a straightforward manner.  If you can optimize someone's
program for speed, you ought to be willing to optimize it for accuracy
as well.

wald-david@CS.YALE.EDU (david wald) (02/08/89)

In article <7800004@gistdev> flint@gistdev.UUCP writes:
>/* Written 12:19 pm  Feb  5, 1989 by atanasoff.cs.iastate.edu!hascall in gistdev:comp.lang.c */
>>   Sure, it works in some simple cases, but how do you propose to
>>   handle:
>>
["do" loop with non-constant start, end and increment]
>>
>>    now we don't know which power of 10 to use, having no "textual"
>>    information from the users program.
>
>From my previous posting: (as George Bush would say: "Read my lips" :-) )
>>>It should be noted that I advocated doing this to "simple" loops where it
>>>works, not to every loop.
>
>I believe we both just said the same thing, so I'll assume you are agreeing
>with me: you just provided an example of a case you can't optimize as I
>stated there would be.
>
>>    Or how about:
>>
>>       do i=0.0, 4.0, 2.0/3.0
>
>The compiler has two choices here:  1. Do the division right away, as you
>just did (something I believe is an error: to use your arguments, "if I wanted
>0.666667 instead of 2/3, I would have said 0.66667!"), or 2. be smart, and
>multiply the denominators through: this is exactly what it is doing in the
>case of decimals.
...
>(How to decide what the smallest integer value to multiply through by is left
>as a 7th grade level arithmetic exercise for the reader.)
>
>In other words, I was already advocating that the compiler do fractions,
>you assumed that I only wanted it to deal with the specific case where
>the denominators in the fractions are powers of 10.  If the user writes
>2/3 in their code instead of 0.667, and the compiler can make use of the
>extra information that 2/3 conveys, then it ought to do so.
>
>I don't think (but I could be wrong: it has happened before :-) ) that
>there is any loop you can write that contains only constants for the
>loop start/end/increment that cannot be converted into an integer
>controlled loop in a straightforward manner.  If you can optimize someone's
>program for speed, you ought to be willing to optimize it for accuracy
>as well.

This bothers me a bit, for the following reason (and I'm switching back
to for(;;) syntax, since I later assume a system with a C-like
preprocessor):

You seem to be advocating different semantics for a for(;;) loop based
on whether the expressions it contains are constant or not.  In a couple
of examples we've seen that the for(;;) construct will loop a different
number of times depending on whether or not the denomonator is
multiplied away.  At what point do you proclaim the compiler "smart
enough"?  Is it enough to deal with constant expressions?  How about
constant expressions hidden by macros?  (Clearly, there's no way of
dealing with the former and not the latter, but you now can have
something which may appear to be in function syntax, but actually turns
into a constant expression.)

What if there's a macro defined as:

#ifdef _SOME_WEIRD_FEATURE_FLAG
#  define macro(x) some_nonconstant_function_of(x)
#else
#  define macro(x) 3
#endif

and you produce code that goes

for(i=0; i<=4; i += 2/macro(j))
    some_expression_affecting_j;

What does your friendly-and-intelligent compiler do?  And how do you, as
programmer, know how long your loop is going to go?  Remember that the
compiler will never see the macro nonsense, only the expressions that
substitute for it.  If you require the programmer to know whether the
macro above evaluates to a constant or not, you are eliminating all the
code-hiding benefits of macros, since the programmer must know what's
inside them.  The programer must also take the feature flag into account
in the middle of a program, perhaps multiple times, whereas the absence
of the "optimization" might allow it to be hidden in a header file.

Finally, as has been stated ad nauseum in this forum, an optimization
should never change the semantics of a program, because you never know
when it's going to be done.  What if a slightly smarter version of this
"optimization" is employed, such that it can find non-constant
expressions that are nevertheless compiler-provably constant for the
duration of the loop.  You get even better benifits, in your terms, but
even more disagreement between compilers that do and don't change their
loop semantics in different circumstances, depending on how good they
are at finding constant expressions.  If I'm writing code, I want to know
how long I'm going to loop, no matter what compiler my code is compiled
with.  That's a fairly basic issue.  If compilers actually "have a
choice" about this sort of interpretation, I don't know this.


============================================================================
David Wald                                              wald-david@yale.UUCP
waldave@yalevm.bitnet                                 wald-david@cs.yale.edu
"A monk, a clone and a ferengi decide to go bowling together..."
============================================================================

ark@alice.UUCP (Andrew Koenig) (02/08/89)

In article <7800004@gistdev>, flint@gistdev.UUCP writes:

> So if your user had written (hascall's previous example below)
> >       do i=0.0, 4.0, 2.0/3.0
> you just multiply everything by 3 to convert it into this:
>         do i=0,12,2
>         float=i/3.0

Sure, this could be done.  It has a nasty side effect, though:

	do i = 0.0, 4.0, 2.0/3.0

will mean something different from

	x = 2.0
	y = 3.0
	do i = 0.0, 4.0, x/y

I would rather have a system whose behavior doesn't change when
I replace a value by another identical value.
-- 
				--Andrew Koenig
				  ark@europa.att.com

henry@utzoo.uucp (Henry Spencer) (02/09/89)

In article <2026@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>	"When someone says 'I want a programming language in which I
>	need only say what I wish done,' give him a lollipop."

There are a number of such languages, actually:  English is an example.
The compilers are known as "graduate students".  Unfortunately, they tend
to be available only in Computer Science departments...
-- 
Allegedly heard aboard Mir: "A |     Henry Spencer at U of Toronto Zoology
toast to comrade Van Allen!!"  | uunet!attcan!utzoo!henry henry@zoo.toronto.edu