[comp.lang.fortran] Side effects in boolean expressions

sjc@key.COM (Steve Correll) (08/15/90)

In article <59110@lanl.gov>, jlg@lanl.gov (Jim Giles) writes:
> From article <2022@key.COM>, by sjc@key.COM (Steve Correll):
> > In article <58237@lanl.gov>, jlg@lanl.gov (Jim Giles) writes:
> >> > 	X .GT. Y .OR. L(Z)
> > [...]
> > C is predictable. The Fortran standard says that the processor _need_ _not_
> > execute the function L if X exceeds Y, and that therefore the program must
> > assume Z is undefined. The C standard for "(x > y) || l(&z)" says that the
> > processor _must_ _not_ execute l if x exceeds y...
> 
> C is predictable only if you know in advance whether X was greater than
> Y.  If I knew that, I wouldn't have tested it.  This is what I meant
> when I said that neither language is defined in such a way as to be
> able to tell a priori (from the first) whether the function would be
> evaluated or not...
> It also means that I can't
> apply the mathematical properties of the 'or' operator to correctness
> proofs of the program.

Perhaps we simply define "predictable" and "a priori" differently, but
consider the following. Even though you don't know the value of x in advance,
the C code is legal and its behavior predictable; the Fortran is neither:

	if ((x < 0.0) || (sqrt(x) < 10.0)) ...
	IF ((X .LT. 0.) .OR. (SQRT(X) .LT. 10.0)) ...

If x is negative, a legal C processor will not call sqrt, but a legal Fortran
processor may or may not--in fact, it could vary with the phase of the moon!
By refusing to define the order of evaluation, Fortran gives the processor
more freedom (e.g. to optimize).

When proving correctness of a C program, notice that:

	if (p0 || p1) s0;

is equivalent to:

	if (p0) s0; else if (p1) s0;
-- 
...{sun,pyramid}!pacbell!key!sjc 				Steve Correll

wsb@boise.Eng.Sun.COM (Walt Brainerd) (08/15/90)

In article <2041@key.COM>, sjc@key.COM (Steve Correll) writes:
> ... the C code is legal and its behavior predictable; the Fortran is neither:
>                                                       ^^^^^^^^^^^^^^^^^^^^^^
> 	if ((x < 0.0) || (sqrt(x) < 10.0)) ...
> 	IF ((X .LT. 0.) .OR. (SQRT(X) .LT. 10.0)) ...
> 
The Fortran code certainly is legal.  The main point is that the _result_
is predictable; how the result is obtained is not, which is exactly the
point of optimization.  The difference is when you rely on function
side effects, important in C, but never should be done in Fortran.
--
Walt Brainerd        Sun Microsystems, Inc.
wsb@eng.sun.com      MS MTV 5-40
                     Mountain View, CA 94043
                     415/336-5991

jlg@lanl.gov (Jim Giles) (08/16/90)

From article <2041@key.COM>, by sjc@key.COM (Steve Correll):
> [...]
> 	if ((x < 0.0) || (sqrt(x) < 10.0)) ...
> 	IF ((X .LT. 0.) .OR. (SQRT(X) .LT. 10.0)) ...
> 
> If x is negative, a legal C processor will not call sqrt, but a legal Fortran
> processor may or may not--in fact, it could vary with the phase of the moon!
> By refusing to define the order of evaluation, Fortran gives the processor
> more freedom (e.g. to optimize).

So, the C definition _requires_ me not to make the optimization I want
to make (namely, starting the SQRT in parallel with the test of X).
Meanwhile, the Fortran (as you say) is completely unpredictable on this
point.

And, when trying to formally analyze the _meaning_ of the program, _neither_
Fortran nor C allows me to treat the 'or' operator as commutative - even
though _mathematically_ it _is_!  To be sure, a short circuit boolean
is occasionally useful - but the ordinary mathematical kind is _much_
more common.  For this reason, the two concepts should be separately
available in a programming language.  For the above, I would prefer
something like:

      if (x < 0) or if (sqrt(x) < 10.0) then ...  !or _outside_ conditions
						  !is short circuited
      if (x < 0 \/ sqrt(x) < 10.0) then ...       !or '\/' operator _inside_
						  !conditions is commutative

Of course, the second of these will frequently die from evaluating sqrt()
on a negative operand.  But, this kind of problem is comparatively rare.

In this example, of course, it is more efficient to do the test as
follows anyway:

      if (x < sqrt(10.0)) then ...

This has the same effect and completely avoids the problem.

J. Giles

patrick@convex.COM (Patrick F. McGehearty) (08/17/90)

In article <60198@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
...stuff about if and or
>> 	IF ((X .LT. 0.) .OR. (SQRT(X) .LT. 10.0)) ...
>
>In this example, of course, it is more efficient to do the test as
>follows anyway:
>
>      if (x < sqrt(10.0)) then ...
>
>This has the same effect and completely avoids the problem.
Actually,
	IF ( X .LT. 100.0) ...
will have the same effect as the original and avoid the problem.

Which shows why people don't make obvious code optimizations.
ANY changes to source or algorithm carry a risk of error.  Sigh.

sjc@key.COM (Steve Correll) (08/17/90)

In article <140684@sun.Eng.Sun.COM>, wsb@boise.Eng.Sun.COM (Walt Brainerd) writes:
> In article <2041@key.COM>, sjc@key.COM (Steve Correll) writes:
> > ... the C code is legal and its behavior predictable; the Fortran is neither:
> >                                                       ^^^^^^^^^^^^^^^^^^^^^^
> > 	if ((x < 0.0) || (sqrt(x) < 10.0)) ...
> > 	IF ((X .LT. 0.) .OR. (SQRT(X) .LT. 10.0)) ...
> > 
> The Fortran code certainly is legal...

I believe that a program which could cause the translator to invoke SQRT with
a negative argument fails to conform to the Fortran 77 standard, because
section 13.10.1, page 15-28 of the X3.9-1978 says:

   Square Root: The value of the argument of SQRT and DSQRT must be greater
   than or equal to zero.
-- 
...{sun,pyramid}!pacbell!key!sjc 				Steve Correll

wsb@boise.Eng.Sun.COM (Walt Brainerd) (08/17/90)

In article <2047@key.COM>, sjc@key.COM (Steve Correll) writes:
> In article <140684@sun.Eng.Sun.COM>, wsb@boise.Eng.Sun.COM (Walt Brainerd) writes:
> > In article <2041@key.COM>, sjc@key.COM (Steve Correll) writes:
> > > ... the C code is legal and its behavior predictable; the Fortran is neither:
                ^^^^^^^^^^^^^
> > > 	if ((x < 0.0) || (sqrt(x) < 10.0)) ...
> > > 	IF ((X .LT. 0.) .OR. (SQRT(X) .LT. 10.0)) ...
> > > 
> > The Fortran code certainly is legal...
> 
> I believe that a program which could cause the translator to invoke SQRT with
> a negative argument fails to conform to the Fortran 77 standard, because
> section 13.10.1, page 15-28 of the X3.9-1978 says:
> 
>    Square Root: The value of the argument of SQRT and DSQRT must be greater
>    than or equal to zero.
> -- 
> ....{sun,pyramid}!pacbell!key!sjc 				Steve Correll

Yes, good point.  By "code being legal", of course, I was thinking
of it being syntactically correct.  Executing it with negative X
is not legal, as pointed out.

The moral is that in C you can write these 2 tests in one line
and in Fortran it must be done with nested IFs, but Fortran allows
optimization of other similar expressions that do not have the property
that they must be done in two lines to make sure everything is OK.
Seems to me like the Fortran choice is "in the spirit of Fortran"
in that it allows for better optimization and puts a little more
burden on the programmer to get it right.
--
Walt Brainerd        Sun Microsystems, Inc.
wsb@eng.sun.com      MS MTV 5-40
                     Mountain View, CA 94043
                     415/336-5991