Checksum: 03744 Lines: 44 Path: utzoo!sq!msb From: msb@sq.uucp (Mark Brader) Date: Thu, 11-Feb-88 20:01:49 EST Message-ID: <1988Feb11.200149.25172@sq.uucp> Newsgroups: comp.lang.c Subject: How not to write a loop Summary: float x; for (x = ...; x < ...; x += ...) /* bad; RTFTEoPS */ References: <560@naucse.UUCP> Reply-To: msb@sq.UUCP (Mark Brader) Organization: SoftQuad Inc., Toronto > Do all bugs bite? This short program ran under unix on a 3b1 (and Ultrix). > float x; > for (x=-3*PI; x < 3*PI; x += PI/8.0) /* Change to x = -3*PI */ > printf ("%f %f\n", x, sin(x)/x); The term "ran" is evidently being used rather loosely here. Since PI/8 is not exactly representable in any finite number of bits, the behavior of the loop after the intended 48 iterations is in fact undetermined. Or as Kernighan and Plauger put it in "The Elements of Programming Style": Floating point numbers should never be used for counting. ... 10.0 times 0.1 is hardly ever 1.0. On the two machines where I tried this, it did in fact loop 48 times and not 49 times, but it did the same if I changed the "<" to "<=". The fact that it *did* loop 48 times is in fact a perfect illustration of the problem. If the behavior of "x" had been exactly what the author intended, the *next* bug would have been triggered: a division by 0 on the 25th iteration. This was avoided on the machines I tried because "x" did not in fact ever become exactly 0. Kernighan & Plauger again: Don't stop at one bug. If you are past the introductory phase of learning to program, and have not done so already, acquire a copy of "The Elements of Programming Style", and *memorize* it. One safe way to write it is: int i; for (i = -24; i < 24; ++i) if (i != 0) { float x = i * (PI/8); printf ("%f %f\n", x, sin(x)/x); } Mark Brader "TeX has found at least one bug in every Pascal utzoo!sq!msb compiler it's been run on, I think, and at least msb@sq.com two in every C compiler." -- Knuth