C vs. FORTRAN

Jim Giles jlg at beta.lanl.gov
Fri Jul 1 02:14:26 AEST 1988


In article <147 at quintus.UUCP>, ok at quintus.uucp (Richard A. O'Keefe) writes:
> [...]
> I didn't say that it was bad.  What I do say is that it is _MISLEADING_.
> In C, for example, most of the operations for which there is special
> syntax correspond to machine operations of similar cost.

It's not misleading.  It means what it says - exponentiation.  It looks
as expensive as an exponentiation operator - no more or less.  If the
syntactical appearance is what you mean by 'special syntax', why does
pow() look any more expensive than abs()?  Divide doesn't look all that
much more expensive than multiply either, but it is.
> 
> What with prototypes and all, an ANSI C compiler is fully entitled to treat
>    [example ...]
> just the same as Fortran 77 would treat
>    [other example ...]

Possibly true.  Also irrelevant.  You are making basically a syntactical
point. So the fact that the future versions of C will fix something
(that IT shouldn't have broke to begin with) is not relevant.

> [...]
> >X**3 is more readable than X*X*X (particularly is X is an expression).
> pow(x,3) isn't _that_ hard to read, either.
> >X**3.5 is more readable than EXP(3.5*LOG(X)).
> True, but again, pow(x,3.5) isn't terribly hard to read, and in any

LISP isn't terribly hard to read either, but it's not what I want to
code numerical expressions in.  The syntax that mathematics uses is
really well suited to the task.  The programming language syntax for
the same purposes should look as similar as possible to the original
math.  There is no reason that I can see to adopt any other rule of
choice in language design.

> case the two expressions X**3.5 and EXP(3.5*LOG(X)) don't mean exactly
> the same thing (may have different over/underflow conditions, yield
> different results, &c).

If X is in range, then LOG(X) is in range.  If X**3.5 is in range, then
certainly 3.5*LOG(X) is.  The expression given overflows (or underflows)
ONLY if the original numbers are out of range or if the final answer
is out of range.
> 
> >If you always do pow(X,Y), the compiler has no choices to make.
> Misleading and soon to be wrong.  Misleading, because the run-time library
> _does_ have some choices to make, and current libraries make them.  Soon

The choice I'm talking about is whether to cause a function call (the
most expensive of all the 'simple' operations).  Doesn't matter what the
subroutine library does, you've already made the expensive call.

> to be wrong, because ANSI C compilers are allowed to detect the standard
> library functions and do special things with them.

Fine, C is fixing something that shouldn't have been broken to begin with.
Now, if it would just add the operator ...

> [...]
> C	Assume that N.ge.2		/* Assume that N >= 2 */
> C	Fragment 1			/* Fragment 1 */
> 	T = A(1)			t = a[0];
> 	DO 10 I = 2,N			for (i = 1; i < n; i++) {
> 	   T = T + A(I) * X**(I-1)	    t += a[i]*pow(x, (double)i);
> 10	CONTINUE			}
> C	Fragment 2			/* Fragment 2 */
> 	T = A(N)			t = a[N-1];
> 	DO 20 I = N-1,1,-1		for (i = n-2; i >= 0l i--) {
> 	    T = T*X + A(I)		    t = t*x + a[i];
> 20	CONTINUE			}
> 
> The two fragments are *not* equivalent.  It is easy to come up with an
> example where fragment 2 correctly yields 1.0 and fragment 1 overflows.
> {I am not asserting that fragment 2 is always the right thing to use!}

An interesting example.  But it makes my point, not yours.  The first
fragment (in either language) looks expensive.  The C fragment also
looks harder to write and maintain - but no more expensive than the
Fortran fragment (this, of course, IS misleading, the C fragment is
probably slower).  Fragment 2 looks clearly preferable in either
language.  The existence of the exponentiation operator doesn't alter
my perceptions about these code fragments AT ALL.
> 
> A good numeric programmer will use X**N __very__ seldom for other than
> constant arguments.

Finally!  Something we agree upon.  But what does this have to do with
the value of placing the operator into the syntax?  Just because it's
seldom used for large or non-constant arguments, doesn't mean it needs
to be arcane or cryptic when it IS used.
> 
> What C _does_ lack that a numeric programmer might miss is a single-
> precision version of pow().  Given
> [...]
> How much faster is float**float than double**double?
> Sun-3/50 (-fsoft)	1.2
> Sun-3/160 (-f68881)	2.5
> Sequent (80387)		1.4
> If this is typical (and I have no reason to expect that it is), the
> [...]

For just multiplies, X*Y, the ratio on the Crays is about 60 (actually
that's an underestimate, since the single precision multiply can be
pipelined).  The ratio for exponentiation must be enormous!  Of course,
this would never be acceptable.  So the Cray C compiler uses SINGLE
instead of DOUBLE for all arithmetic.  I don't know if it even HAS
a way of doing real double.  (Cray single has ~14 decimal digits of
precision.)

My point is that if you're suggesting that languages should be designed
to protect a small number of naive users from making simple efficiency
errors - you're wrong.  Programming languages should be designed to
allow _good_ programmers to write and maintain their codes as productively
as possible.  After all, this is why C, with its terse (and sometimes
cryptic) syntax is so popular.  If you really want to protect naive
users, you should lobby for removal of expressions with side-effects
from C.

J. Giles
Los Alamos



More information about the Comp.lang.c mailing list