How not to write a loop

Mark Brader msb at sq.uucp
Fri Feb 12 11:01:49 AEST 1988


> 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 at sq.com		 two in every C compiler."	-- Knuth



More information about the Comp.lang.c mailing list