How not to write a loop, revisited

Peter Klausler pmk at hall.cray.com
Wed Mar 2 02:36:29 AEST 1988


In article <832 at unmvax.unm.edu>, mike at turing.UNM.EDU (Michael I. Bushnell) writes:
> In article <296 at draken.nada.kth.se> d86-ctg at nada.kth.se (Claes Thornberg) writes:
> >... And thinking of simple things
> >like not using real variables in for-loops isn't that hard...
> 
> I see NOTHING which precludes:
> 	float x;
> 	for (x = 0; x < 20; x += .5)
> 		printf("%f ", x);
> The output would, of course, be
> 	0.0 0.5 1.0 ... 19.0 19.5
> But maybe the condescending poster didn't mean loop control variables.

No, I'm sure that Claes did, for the use of floating point in loop control
is a nasty habit that produces very unportable code. Michael's example
might be all right, as the loop increment is a power of two, but, in general,
the construct

	float start, end, incr, var;
	for (var=start; var<end; var+=incr)
		/* body */

can't be trusted to execute exactly (int)((end-start)/incr) times.


Kernighan and Plauger's "Elements of Programming Style" states
		10.0 times 0.1 is hardly ever 1.0.

I submit that
	0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 is hardly ever
	10.0 times 0.1, and neither need be 1.0.


Let me back this up with a real example. Try this program on your
favorite C implementation:

main (argc, argv)
int argc;
char **argv;
{
        float s, e, i, v;
        int c = 0;
        sscanf (*++argv, "%f", &s);
        sscanf (*++argv, "%f", &e);
        sscanf (*++argv, "%f", &i);
        printf ("start=%f, end=%f, incr=%f\n", s, e, i);
        for (v = s; v < e; v += i)
		c++;
        printf ("%d iterations executed; expected %d; final value=%f",
                c, (int)((e-s)/i), v);
        }


I ran this on three of our development systems, and saw:

	cray-2% a.out 0 1 0.1
	start=0.000000, end=1.000000, incr=0.100000
	10 iterations executed; expected 10; final value=1.000000

	cray-ymp% a.out 0 1 0.1
	start=0.000000, end=1.000000, incr=0.100000
	iteration 11, v=1.000000
	11 iterations executed; expected 10; final value=1.100000

	sun-3% a.out 0 1 0.1
	start=0.000000, end=1.000000, incr=0.100000
	10 iterations executed; expected 9; final value=1.000000

For "a.out 0 1 0.01", the Cray-2 executed 100 iterations, while the
Y-MP and Sun-3 did 101.


This is not a bug of any sort, although compiler writers are
used to getting problem reports on it. This is a consequence of the
inexactitude of finite-precision floating-point arithmetic,
and its different hardware/software implementations.

If this scares you, good! Floating-point can be a nasty nemesis of
the numerically naive. Claes' advice is sound:

		USE INTEGERS FOR COUNTING.

Peter Klausler @ Compiler Development, Cray Research, Inc.
	...!{ihnp4!cray,sun!tundra}!hall!pmk



More information about the Comp.lang.c mailing list