Dunno; I've never compared the speed for 3- and 4-D arrays with **a vs.
a[N][M]. Do you expect a big effect, and if so, why? Again, if the
arrays are sparse and elements referenced by index or pointer arrays,
both 2-D and 3-D still see a performance hit, in FORTRAN or C.
D> How about complex arithmetic?
Depending on the app, and the need for good localty of access, in C I
either use arrays of the pre-defined complex structure or set up
separate arrays of the parts. Complex numbers are much more convenient
in FORTRAN, but I've never compared the relative speeds. As I said,
there are trade-offs.
---
ÅŸ SPEED 1.40 #1564 ÅŸ Du sublime au ridicule, il n'y a qu'un pas...
--
The Albuquerque ROS - (505) 296-3000
>D> What happens when you have to deal with 3 and 4-dimensional matrices,
> > which are not that unusual in Fortran codes?
>
>Dunno; I've never compared the speed for 3- and 4-D arrays with **a vs.
>a[N][M]. Do you expect a big effect, and if so, why? Again, if the
>arrays are sparse and elements referenced by index or pointer arrays,
>both 2-D and 3-D still see a performance hit, in FORTRAN or C.
The idea is that in order to access an element of a 4 dimensional array
in C you need 4 memory accesses, while in Fortran 1 is enough. Quite a
difference and memory accesses tend to be expensive on most RISC
systems.
The complete absence of pointers in the Fortran version of the code allows
the optimizer to be considerably more aggressive than the C one, which
has to deal with a lot a pointers which can create a lot of potential
aliasing.
Sparse arrays are usually treated as compact arrays in Fortran, for
efficiency reasons. Some operating systems (e.g. AIX and DEC OSF/1)
support lazy swap allocation, so only the used parts of the sparse arrays
actually get allocated.
>D> How about complex arithmetic?
>Depending on the app, and the need for good localty of access, in C I
>either use arrays of the pre-defined complex structure or set up
>separate arrays of the parts. Complex numbers are much more convenient
>in FORTRAN, but I've never compared the relative speeds. As I said,
>there are trade-offs.
The Fortran compiler "knows" about complex arithmetic, the C one doesn't.
Hence the difference in the efficiency of the generated code. The
complex intrinsics from the library can be implemented more efficiently
than any C version cooked by the programmer.
Dan
--
Dan Pop
CERN, CN Division
Email: Dan...@mail.cern.ch
Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland
>Dunno; I've never compared the speed for 3- and 4-D arrays with **a vs.
>a[N][M]. Do you expect a big effect, and if so, why?
Assume an array A(M,N) which is accessed as A(I,J).
In C, this could be expressed as
a[(i-1)+(n-1)*(j-1)]
When, for example, you access these elements as A(I,1), A(I,2), ...
you can get the array index via a simple addition by moving all
the constants out of a loop, as in:
inc = m;
ind = i;
for (j=0; j<n; j++) {
a[ind] ...;
ind += inc;
}
On special hardware (i.e. vector computers), this can be done even
more effectively.
Compare this to a[j][i], which goes like this:
for (j=0; j<n; j++) {
ap = a[j]; /* <--- one pointer dereference */
val = a[i]; /* <--- second pointer dereference */
}
No guarantee of constant stride, nothing...
--
Thomas Koenig, Thomas...@ciw.uni-karlsruhe.de, ig...@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.
Exactly! I've been using it for several years. No need to access two times
to get 2D memory.
#define pd(a,b) pd[nr*(b-1)+a]
void jac1(..........................)
{
pd(1,1) = 0.0e0;
pd(1,2) = 1.0e0;
pd(2,1) = -6.0e0*y[1]*y[2] - 1.0e0;
pd(2,2) = 3.0e0*(1.0e0 - y[1]*y[1]);
return;
}
Whoa. This is true only if your C application implements 4d arrays
using dope arrays. It is perfectly legitimate to declare:
float ar[ DIM1 ][ DIM2 ][ DIM3 ][ DIM4 ];
Any element can be dereferenced by means of a single redirection.
The real problems with this, as I see it, are:
1. You've got to do the pointer arithmetic yourself,
unless the dimensions are indeed known at compile time.
2. In a set of nested loops, you'd probably code the
computation of the offset separately for each access
in the inner loop, most likely using a macro.
The compiler might not be smart enough to decompose
the complicated offset expression into a single
constant-stride pointer addition, nor should it, for
unoptimized code. A Fortran compiler would nearly
certainly do this decomposition, even for unoptimized
code.
All this is over and above any pointer-aliasing inhibitions to
C optimization.
Incidentally, the now defunct NCEG (Numerical C Extensions Group)
proposed an extension to C that would allow run-time array dimensions
to be declared, as in the Fortran example:
SUBROUTINE FOO( AR, N1, N2, N3, N4 )
REAL AR( N1, N2, N3, N4 )
DO 40 I4 = 1, N4
DO 30 I3 = 1, N3
DO 20 I2 = 1, N2
DO 10 I1 = 1, N1
C *** first index moves fastest, for efficiency:
AR( I1, I2, I3, I4 ) = <whatever>
10 CONTINUE
20 CONTINUE
30 CONTINUE
40 CONTINUE
...
I believe the proposed C prototype syntax was rather bizarre, to
fit C's normal requirement that a variable must be declared
before used, so that a C function for the above would look
something like:
void foo( int n1, int n2, int n3, int n4; float ar[n1][n2][n3][n4] ) {
int i1, i2, i3, i4;
for( i1=0; i1<n1; ++i1 ) {
for( i2=0; i2<n2; ++i2 ) {
for( i3=0; i3<n3; ++i3 ) {
for( i4=0; i4<n4; ++i4 ) {
/* last index moves fastest, for efficiency: */
ar[ i1 ][ i2 ][ i3 ][ i4 ] = <whatever>;
}
}
}
}
}
The call to foo would then look like:
foo( ar, n1, n2, n3, n4 );
and with this call, normal ANSI type-conversion of variables would
occur.
I may not have the syntax exactly right, but it was something like the
above, I think. I'd be happy to stand corrected, if not.
There was some discussion on the NCEG mailing list about why this
never made it into the ANSI C spec. I believe it was raised, but
dismissed because of insufficient past experience with the feature.
This extension would make C much easier to use for many
numerical applications. It doesn't address the aliasing problem,
but it does address a significant ease-of-use issue, and possibly
issues of optimization of pointer-dereferencing as well.
I don't know what the future of this proposal is going to be;
presumably, it's been forwarded to the ANSI C committee.
Regarding the aliasing problem, most readers probably are aware
that there was a proposal for a "noalias" keyword. The particular
form of the proposal was ill-conceived, and died when Dennis Ritchie
wrote a cogent and pungent critique of it. Better ways of
accomplishing the desired end are no doubt conceivable, but I think
the fate of the original proposal cast a pall over the whole effort.
-P.
--
************************ The secret of life: *************************
*Peter S. Shenkin, Box 768 Havemeyer Hall, Chemistry, Columbia Univ.,*
* New York, NY 10027; she...@columbia.edu; (212) 854-5143 *
************* If you find a loose thread, don't pull it. *************
>In comp.lang.fortran, hws...@abq-ros.com wrote:
>
>>Dunno; I've never compared the speed for 3- and 4-D arrays with **a vs.
>>a[N][M]. Do you expect a big effect, and if so, why?
>
>Assume an array A(M,N) which is accessed as A(I,J).
>In C, this could be expressed as
>
> a[(i-1)+(n-1)*(j-1)]
Yeah, that's the technique used by f2c. f2c, at least, doesn't claim to
produce human-readable output :-)
Any decent c numerical analysis book should mention 'array
arithmetic.' However, obviously you don't have one...
------------------ fortran ------------------
integer iii
dimension iii(2,2,2)
data iii/ 1,2,3,4,5,6,7,8/
do 1000 i=1,2
do 1000 j=1,2
do 1000 k=1,2
write(6,100) i,j,k,iii(i,j,k)
1000 continue
100 format(2x,i1,i1,i1,2x,i2)
end
---------------------- c --------------------
#include <stdio.h>
#define pd(a,b,c) pd[nm*(nr*c+b)+a]
int main()
{
int i,j,k,nm=2,nr=2;
int pd[2*2*2] = {1,2,3,4,5,6,7,8};
for(i=0;i<=1;i++)
for(j=0;j<=1;j++)
for(k=0;k<=1;k++)
printf(" %d%d%d %d\n",i+1,j+1,k+1, pd(i,j,k) );
return 0;
}
--------------------- f2c -------------------
i(i,j,k) = iii[i + (j + (k << 1) << 1) - 7]
------------------ results ------------------
* fortran * *** c *** ** f2c **
111 1 111 1 111 1
112 5 112 5 112 5
121 3 121 3 121 3
122 7 122 7 122 7
211 2 211 2 211 2
212 6 212 6 212 6
221 4 221 4 221 4
222 8 222 8 222 8
-------------------- a tip -------------------
for 2-d array, one can define following in his/her program.
#define pd(a,b) pd[nr*(b-1)+a]
So, does my translated (from fortran) c source be readable
for you? Did C language need three locations to translate
a fortran 3-d array?
Shallow, shallow....
Woon-Chul Choi
I would think that any decent c numerical analysis book would
use the following definition for pd references.
#define pd(a,b,c) pd[nm*(nr*(c)+(b))+(a)]
otherwise the following code would not execute properly and could
be very difficult to debug in the wrong situation.
dummy = pd(i,j,k+1)
Either way you are, IMO, hacking normal code into abnormal
code to increase performance, a required evil at times but something
to be avoided when at all possible. Why stop there? You did not
collapse the loops as well, as in:
C -- do NOT turn on array bounds checking if you do this!!!
do 1000 i=1,2*2*2
write(6,100) iii(i,1,1)
1000 continue
-------- f77/c barrier------------------
for(i=0;i<2*2*2;i++) printf(" %d\n",pd[i]);
Save the stupid multiplications and insure that even the dumbest
compiler (oops, an absolute, most compilers?) can see you are indexing
sequential memory locations and optimize based on that. Most real numerical
codes don't give a squat about outputting indexes until the bitter end,
so I ignored that in your example.
WHAT, thats "ugly" and hard to understand you say? Using clever #define
just sweeps the "ugly" details under the rug, so to speak. What happens
when you have 500 different such arrays in a non-toy problem, 500 #defines?
Would you really appreciate using a debugger on highly pre-processed code?
I wouldn't. My point, a HACK is a HACK, no matter how much sugar you
put on it to disguise its bitter taste. Using 1D arithmetic to show
the efficiency of (2+)D arithmetic is pointless. Work-arounds almost always
makes code more difficult to maintain, more bug prone, difficult for
others to use, etc, but they are needed some times. Be a real programmer,
admit your HACKing, comment the hell out of it and be able to defend
why you HACKed your code.
HACKer Tom
Well, no, because you didn't use a C 3-d array. You linearized the array,
and used a macro to make it look like an array reference (except for
changing [] to () that is ;-). Fortran code from the '60s looked like
this too, and that is presumably why C was designed this way. However, by
the mid '70s fortran compilers generally treated multi-dimensional arrays
correctly, and this kind of kludge was no longer necessary (in fortran
that is).
However, in f77, the standard defined a more generalized array declaration:
dimension a(ilow:ihi, jlow:jhi, klow:khi, llow,lhi)
for example for a 4-d array. All ranges are integer variables (not
constants). I'd be interested in seeing a C macro that makes this kind of
generalized array expression comprable to fortran
a(i,j,k,l) = ...
And if you come up with one, try to convince me that it is simple enough
to optimize by the compiler, and to maintain by the programmer (or by
several programmers). Once you've done this, you can say that C is
comparable to f77 (an 18 year old language). Then we'll show you what f90
can do! ;-)
Oh yeah, and don't forget in these macro definitions that division in C
involving negative integers is not well defined, so you must account for
the possibility that your machine rounds the unexpected way.
>Shallow, shallow....
Sort of like that post a few weeks ago that claimed complex exponentials
had no meaning, so it was useless for a language to allow them. ;-)
$.02 -Ron Shepard
Oh, the joy of maintaining hundreds of lines of "#define"s, one for
each multi-dimensional array.
Oh, the lauded "compact expressive power" of C! :^)
I believe the proposed C prototype syntax was rather bizarre, to
fit C's normal requirement that a variable must be declared
before used, so that a C function for the above would look
something like:
void foo( int n1, int n2, int n3, int n4; float ar[n1][n2][n3][n4] ) {
Note that GNU CC implements the above as an extension.
In working with g77 and the gcc back end, I realized that the above was
somewhat inadequate in the C milieu. Specifically, suppose every argument
above was changed to be a pointer to the target instead (int *n1, int *n2,...,
float *ar[...]), and then suppose that sometimes the caller wanted to pass
a null pointer, or some other condition existed such that the pointers were
not valid and/or the values to which they pointed were not valid.
This poses a problem, because the above construct, as implemented by gcc
and I believe as it would have to be implemented as proposed, causes
the automatic generation of code to evaluate the appropriate expressions
before any other code is executed. But without a way for the function
definition to express conditionals that would prevent the automatic
code from being executed (say, on a per-argument basis), there's a
significant loss of flexibility here. For example, the C equivalent of
Fortran 90's omitted arguments could not be straightforwardly implemented
using this extension.
The example I like to use would, in Fortran, look like:
SUBROUTINE X(A,I,J)
REAL A(I/J)
...
END
If A is omitted, I and/or J may be omitted as well, and I presume that
(with the proper interface stuff that I haven't shown) Fortran 90 would
do things "right". That's because the compiler knows how it handles
omitted arguments, and the compiler is generating the implicit code
to calculate the dimension expression in the prologue so the size
of the array doesn't appear to change during execution of the procedure
if *I and *J change.
But the obvious C rendition of the above (coded to perhaps actually be
directly substituted for the Fortran version on most architectures)
would look like:
void X(int *I; int *J; float *A[*I/*J], int *I, int *J)
{ ... }
The code shown by "..." would begin implicitly with an evaluation of
the expression *I/*J, the result being stored in a temp that denotes the
size of the *A array (note I might have the precedence wrong -- I keep
forgetting this stuff :-).
Now, what if the caller is allowed to omit the A, I, and J arguments?
How is this done in a straightforward way? Passing NULL arguments won't
work, because the implicitly generated code doesn't know to check for
that. Even if it did, unlike with Fortran, in C there can be many other
valid ways to pass things around, such that perhaps the caller isn't
a Fortran routine, wants to pass a non-NULL value in for the *A pointer,
but nevertheless is not passing in the A array as we would know it.
Even having the caller handle omitted arguments by passing pointers to
binary zeros (for example) wouldn't work, because the above example would
involve a divide-by-zero error, which could be as bad as a null-pointer-
dereference error.
A solution might be to allow an extra specification for any adjustable
dummy array in the C code that consists of an expression to be evaluated
and used to determine (if non-zero) whether to evaluate the dimension
expression(s). E.g.:
void X(int *I; int *J; float *A[*I/*J] evaluateif(A != NULL),
int *I, int *J)
{ ... }
Or perhaps requiring the code to be written so A is just "float *A" and
an inner block is coded for the "...":
void X(float *A, int *I, int *J)
{
if (A != NULL)
{
float *A[*I/*J] = A;
...
}
}
But that is even uglier.
Ugly, too, is that the proposed notation amplifies a nastiness in the
C syntax, specifically, the overloading of the comma as both a
binary operator and a list-item separator. Normally, C text like
"foo, bar; bletch, barf" treats the semicolon as a lower-precedence
token than the comma, but in cases like the above (using the proposed
syntax), the opposite is true. That is, instead of "(foo, bar);
(bletch, barf)" the examplet is treated in that case as "foo, (bar; bletch),
barf", which is kind of sad. AFAIK, ANSI C doesn't allow the notation
anyplace where it would have the latter interpretation, and perhaps
it isn't wise to change it so it does.
But, who knows, maybe adding such ugliness to C might make it more
attractive to Fortran programmers? (Major :-)
Regarding the aliasing problem, most readers probably are aware
that there was a proposal for a "noalias" keyword. The particular
form of the proposal was ill-conceived, and died when Dennis Ritchie
wrote a cogent and pungent critique of it. Better ways of
accomplishing the desired end are no doubt conceivable, but I think
the fate of the original proposal cast a pall over the whole effort.
I hope not. I'd love to read Ritchie's critique, since when I first
saw "noalias" in the proposal my reaction was "how can that possibly
get anything useful right??" without being able to put my finger on
all the things that were wrong with it. I was really glad it was
dropped. But, it would be highly useful to extend the C language
to include the concept that not everything lives in the same physical
memory, which is essentially what "noalias" is saying (and what
Fortran already understands).
What I'm not so sure of is whether it'll be possible to extend
C in ways sufficiently elegant to be worthwhile to get these various
features (especially noalias). Note that already the proposed C syntax
for adjustable arrays is much wordier than the equivalent Fortran syntax
when compared to the simpler, non-adjustable-array example. It might not
be worthwhile to extend C so that expressing more generality than the language
already offers (such as a single-address-space model) can be done in
a portable, readable way, for example, or so that expressing the notion
of adjustable arrays can be done (since that can be coded by hand anyway).
I wonder how much C code out there is using the gcc extension for
adjustable arrays? (Lots of Fortran code uses adjustable arrays.)
It might turn out that it is best to leave both languages with their
default views of their computing universes, and suggest to people
insisting on using one of them for the others' purpose to simply switch.
E.g. C views all addressable items as being in the same address space,
and that is a highly useful view for many applications (especially for
system tools); while Fortran views items such as dummy arguments as
being passed in separate memories, for most intents and purposes, and
that is a highly useful view for many other applications (especially
for generating highly optimized code for RISC, VLIW, and parallel
systems). Other such philosophical contrasts exist as well (e.g.
Fortran's .AND. is more general and thus more optimizable than C's
&& and &, same with .OR. vs. || and |). These are pretty fundamental
points, and they affect how very tiny chunks of code are interpreted
(e.g. "F() .AND. G()" being, computationally, fundamentally quite
different than "f() && g()" or "f() & g()", even though they are
thought of pretty much the same ways by the programmers). Adding
language to alter such tiny chunks to change the fundamental
interpretations is likely to result in very ugly, unnatural (and thus
unmaintainable) code.
(The general way I'd say Fortran is fundamentally different than C,
especially in these areas, is that Fortran offers more general
specifications of how an implementation carries out operations than
does C. The result is that the Fortran programmer is given less
information on how the operations will work at run time than the
C programmer is given. C offers more specific specifications,
allowing the programmer to more easily specify exactly what is to happen
when, but not as easily specify Fortran-like general operations that
a compiler might optimize even better than hand-coded C. I think
C ends up being more programmer-friendly to this extent, given that
both languages are generally at the same level of expressiveness,
because the programmer is more likely to get the behavior he expects;
whereas Fortran ends up being more optimizer-friendly, because the
program is not normally as restrictive about what the optimizer can
do to it.)
--
James Craig Burley, Software Craftsperson bur...@gnu.ai.mit.edu
>Regarding the aliasing problem, most readers probably are aware
>that there was a proposal for a "noalias" keyword. The particular
>form of the proposal was ill-conceived, and died when Dennis Ritchie
>wrote a cogent and pungent critique of it.
People who are interested in reading this cirtique can get it
from http://www.lysator.liu.se/c/dmr-on-noalias.html.
> I wonder how much C code out there is using the gcc extension for
> adjustable arrays? (Lots of Fortran code uses adjustable arrays.)
Adjustable-size arrays or pointers is really bread and butter for
people doing numerical work. It has been part of fortran as long
as I can remember, but is is missing in C. A large part of the discussion
in comp.lang.fortran on languages suitable for HPC has been focused on this point.
I actually posted an article in com.lang.c a few days ago where I
tried to initiate a discussion on which features C programmers would
like to see in a forthcoming standard, and I proposed adjustable-size
pointers as my favotite addition. There has been no response to my article.
However, I maintain the view that adjustable-size pointers are needed
in order to make the C language competitive for numerical work. The standard
C solution with a double pointer and a pointer array (double **a) is not
efficient enough when one has to loop over the "slow" first index a[i][j].
In most cases of interest the row size in not known at compile time
to allow the declararation of a matrix of the form double a[ROW][COL].
As I see adjustable-size pointers could be added rather seemlessly to the C language
without changing its spirits. As pointed out in this group gcc already supports it.
I understand that some proposal in this direction
were considered but not adopted by the ANSI committee. I would like to see an
addition that would allow something like the following:
void f(int n, int m)
{
double *a = malloc(n*m*sizeof(double));
double (*b)[m] = (double (*)[m])a; /* tell compiler how to index into array a */
/* in C++ perhaps
double (*b)[m] = new double[n][m]; */
/* do something useful */
}
The idea would be that the indexing scheme used for reads and writes through
b is determined when thread passes through its declaration, regardless of subsequent
values of m.
Assumed-sized pointers should also be allowed in function prototypes, like
void f(int n, int m, double (*a)[m]);
The above syntax is essentially identical to the one used for ordinary fixed-size array pointers.
In the example the compiler knows anyway that m is a variable, so why using a special
syntax for pointing that out to it.
It is a real pain to do this indexing by hand, as C and C++ programs must in order
to write efficient code.
Carl-Olof Almbladh
Department of Theoretical Physics
Lund University
This is not surprising, since it was Richard Stallman who suggested
this syntax. Many of us, led by the folks at Cray, disagreed, and
thought that it ought to be enough to say:
void foo( float ar[n1][n2][n3][n4], int n1, int n2, int n3, int n4 )
that is, to delay the binding of n1, n2, n3 and n4 until the end of
the prototype was reached. Cray had already implemented the extension
in this way. But I believe that in the end, it was Stallman's
suggestion that was adopted. To some of us, it seemed that this
was forcing the programmer to jump through hoops in order to make
life easier for the compiler writers. But after all, this has
to be done only in the function definition and prototype; using
the function is still easy for the user.
(BTW, I'm still not certain that this is exactly what was adopted in
the end....)
>In working with g77 and the gcc back end, I realized that the above was
>somewhat inadequate in the C milieu....
>...For example, the C equivalent of
>Fortran 90's omitted arguments could not be straightforwardly implemented
>using this extension...
Craig,
Nobody said that this was supposed to provide a drop-in for arbitrary
Fortran routines, or to facilitate the translation of Fortran code
into C. The motivation was to facilitate numerical programming in C,
not mixed-language programming, and not F->C tranlation. It does, in
fact, facilitate these two things in a limited way, but nothing you've
said contradicts the assertion that it performs its stated purpose well.
>Ugly, too, is that the proposed notation amplifies a nastiness in the
>C syntax, specifically, the overloading of the comma as both a
>binary operator and a list-item separator. Normally, C text like
>"foo, bar; bletch, barf" treats the semicolon as a lower-precedence
>token than the comma, but in cases like the above (using the proposed
>syntax), the opposite is true. That is, instead of "(foo, bar);
>(bletch, barf)" the examplet is treated in that case as "foo, (bar; bletch),
>barf", which is kind of sad.
I agree with you that this is a peripheral issue, but I don't think what
you say is correct. Everything before the semi-colon is treated as
a "tentative declaration" to be pushed onto the parsing stack until
it's encountered again after the semicolon. When it's encountered
after the semicolon, it's restored to its proper position in the
prototype. In any case, commas in prototypes, or in pre-ANSI
function definitions, are quite different from commas in executable
code.
....
>What I'm not so sure of is whether it'll be possible to extend
>C in ways sufficiently elegant to be worthwhile to get these various
>features (especially noalias)....
It might not be; I'm not sure.
>... Note that already the proposed C syntax
>for adjustable arrays is much wordier than the equivalent Fortran syntax
>when compared to the simpler, non-adjustable-array example.
Yes, due only to the protests of C compiler writers. Even so, as
I mentioned, the *use* of the function is no wordier than before --
only the function definition and prototype are wordier.
>...It might not
>be worthwhile to extend C so that expressing more generality than the language
>already offers (such as a single-address-space model) can be done in
>a portable, readable way, for example, or so that expressing the notion
>of adjustable arrays can be done (since that can be coded by hand anyway).
Yes, but it's tough to do for higher-dimensional arrays, and especially
tough to write loops in an optimized or readily optimizable manner.
>I wonder how much C code out there is using the gcc extension for
>adjustable arrays? ....
None of mine, but if this ever becomes part of ANSI, I'll certainly
use it.
>...(Lots of Fortran code uses adjustable arrays.)
All of mine.
>It might turn out that it is best to leave both languages with their
>default views of their computing universes, and suggest to people
>insisting on using one of them for the others' purpose to simply switch.
Well, as a simple programmer, C and Fortran don't seem so philosophically
different to me. My view of the programming universe is pretty much
the same when I use C and when I use Fortran. It's just that there
are some things that are easier to do in C, and some that it's easier
to do in Fortran. Incremental changes like automatic arrays for C
would help me out a lot when I have an application most of which is
ideally suited for C but some of which is ideally suited for Fortran.
It simplifies my life in many ways not to have to resort to mixed-
language applications.
>...Other such philosophical contrasts exist as well (e.g.
>Fortran's .AND. is more general and thus more optimizable than C's
>&& and &, same with .OR. vs. || and |).
How?, restricting ourselves to .AND./&& and .OR./||. I really
wish Fortran required these to be parsed left-to-right, so I
could write in Fortran:
IF( M.GT.0 .AND. A(M).NE.0 )THEN...
instead of having to resort to:
IF( M.GT.0 )THEN
IF( A(M).NE.0 )THEN...
Again, viewed pragmatically, this is just a pain in the ass, IMHO,
compared to C. But I think you have more than this in mind, and
I'd like to know what.
This topic keeps coming up: and was just discussed a few days back in either
comp.lang.c or comp.lang.c.moderated, where I had written a longish post.
I ignored this post as it was a repetition too close. In any case,
1) In C, `types' are static: and they have certain properties... the most
important of them being its size. It is perfectly valid in C, to say
sizeof(X) where X is a typename denoting a complete type, or sizeof Y where Y
is an expression. At the moment, both of these lead to `integral constant
expressions' (i.e. compile time constants): allowing complete array types to
have an index which is a variable will take away this property of sizeof
being a compile time constant. sizeof then may need to evaluate expressions
(i.e. if an array bound is an expression).
Calling variably dimensioned arrays as an incomplete type will mean that one
will then be able to _define_ objects with `incomplete' types: not a very
pleasant idea.
2) In C, one can declare variables with static duration, and they can share a
scope with transient `automatic' variables. One would need rules to disallow
dimensioning of static variables (and initialization as well in that case:
at the moment static variables can be initialized only with constants) from
automatic variables.
3) We have to disalllow
int f(int); static int n = sizeof(int[f(3)])
probably by declaring sizeof is not a compile time constant if it operates on
a (variable of or) type with non-constant dimension.
4) We have to disallow pathologies like
int n = sizeof(int[n]); probably by demanding that the dimension have a well
defined value (either because of a previously _completed_ initialization, or
because it was declared and given a value in an outer block, or by parameter
passing or as a side effect of a previous declaration.)
In addition, one needs to make a number of arbitrary decisions:
1) Currently, in C, an expression is allowed anywhere (in value context)
where a variable is allowed: the only admitted difference is between
`constant' (i.e. compile time constant) and `non-constant' expressions. If we
stick to this rule, then we have to determine what the following expression
means:
int n = 5; char a[n++][n++], b[++n];
(if non-constant expressions are allowed, current rules will make the above
to be same as char a[5][6], b[8]; int n = 8; because there are sequence points
at the end of the complete expressions n++ and ++n).
2) One has to decide what the following does:
{
static int n = 5; /* n is initially 5, but is saved between invocations */
typedef int X[n++]; /* X is the same type as an array[n] of int */
n++;
{ X b, c; /* is b int[7], or int[5]? c? What about in the next invocation?*/
X d; /* And this? */
}
}
But, for all this: it is a good proposal. I already use the GNU extensions in
this regard whenever possible: and would like to see it become standard.
Cheers
Tanmoy
--
tan...@qcd.lanl.gov(128.165.23.46) DECNET: BETA::"tan...@lanl.gov"(1.218=1242)
Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87544-0285,USA H:#3,802,9 St,NM87545
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003 voice: 1 (505) 665 4733 [ Home: 1 (505) 662 5596 ]
The hall-mark of the trade-off between fortran and C ! In C, a simple compact
expression usually `expresses the programmers intent', and the compiler
better get it right, even if that generates slow code! In Fortran, a simple
compact expression permits `the compiler to optimize as much as possible' and
the user will speak in tongues if he has to speak something complicated.
Imagine you are on a machine which has a separate memory fetch and ALUnits,
and M sits in the register, and a complicated calculation precedes this
statement. Fortran allows you to start off the memory fetch of A(M) even
before the ALU is free and can test M.GT.0. The idea is that if the user
wants to force a wait, (s)he can always use the second form. This is somewhat
like the C `&' operator used in a logical context: rather than the `&&'
operator.
On the other hand, IF (F() .AND. G()) THEN... may fail to evaluate
F or G, whereas the & operator in C will always evaluate both
operands. This is the reason why functions with side-effects are a bad idea
in Fortran: they can be eliminated (at least according to the standard). They
are perfectly safe in C.
But, as I said, this is not an uncharacteristic situation: e.g. aliasing of
variables (e.g. same variable as multiple parameters: or as common and
parameter) leads to undefined behaviour in fortran (if any is modified:
fortran 90 may need access to the other one for undefined behaviour; I do not
know) whereas that is perfectly safe in C. It may be easier to write
a non-conformant optimizer for C: and it is easier to write an incorrect
program in Fortran :-)
Array boundaries could (and should, IMHO) be restricted to (constant?)
integral lvalues.
void foo( const int n1, const int n2, const int n3, float ar[n1][n2][n3]) {
}
(which should also make the compiler's job easier ;-)
>and then suppose that sometimes the caller wanted to pass
>a null pointer, or some other condition existed such that the pointers were
>not valid and/or the values to which they pointed were not valid.
Passing 0 as an array dimension would signal this clearly enough,
I think.
I don't think there is a real need, in C, for being able to
specify array bounds as expressions; the programmer can take care
of that.
Yes, it's less elegant than the Fortran version, but it would be a BIG
win over what's currently available in C.
Hmm... just wondering... what should the syntax to the eqivalent
of an ALLOCATABLE array look like? Do we finally get a pointer
to an array as being different from the first element of
an array? :-)
[...]
>But the obvious C rendition of the above (coded to perhaps actually be
>directly substituted for the Fortran version on most architectures)
>would look like:
>
> void X(int *I; int *J; float *A[*I/*J], int *I, int *J)
^^
I see that you've inadvertantly started a C comment here. Nice to see
that even experienced C programmers sometimes fall into this trap too. ;-)
$.02 -Ron Shepard
I am rather happy to see a response to my favorite addition to the C
standard. Of cource there will be many issues that must be clarified,
and no one likes to have the C language messed up with lots of exceptions.
Although I am really not a computer scientist I will try to give ways
out of the difficulties pointed out above.
First, I really suggested adjustable-sized array POINTERS (*a)[m] to
be used for fetching data from existing arrays gotten from malloc
or passed as arguments, I did not suggest adjustable-sized ARRAYS
a[n][m] whose size is unknown at compile time. The thing that is unknown
at compile time is how the pointer should be scaled in address calculations.
Would it not reasonable to view this new kind of pointer as a new type,
different in type from any fixed-size array pointer to the same base type?
It is true, though, that given the declaration
double (*a)[n];
sizeof(*a) has to be calculated as n*sizeof(double) at run time. I cannot
really judge how serious it would be that some sizeof expression are not
compile-time constants.
It seems to me that the remaining difficulties could be eliminated
by requirering that the arguments in a adjustable-sized array pointer
must be a const integral expression, possibly initialized by
a non-constant expression:
void f(int m, int n)
{
const int nn = n/2;
double (*a)[nn] = malloc(m*sizeof(*a));
/* etc */
}
Let me conclude by reiterating that an extension to C is very important
in most numerical work, and I hope that will be seriously considered by
the C community
Carl-Olof Almbladh
c...@teorfys.lu.se
In article <BURLEY.95J...@apple-gunkies.gnu.ai.mit.edu>,
Craig Burley <bur...@gnu.ai.mit.edu> wrote:
>In article <3rhpp9$4...@sol.ctr.columbia.edu> she...@still3.chem.columbia.edu (Peter Shenkin) writes:
>
> I believe the proposed C prototype syntax was rather bizarre, to
> fit C's normal requirement that a variable must be declared
> before used, so that a C function for the above would look
> something like:
>
> void foo( int n1, int n2, int n3, int n4; float ar[n1][n2][n3][n4] ) {
>
>Note that GNU CC implements the above as an extension.
This is not surprising, since it was Richard Stallman who suggested
this syntax. Many of us, led by the folks at Cray, disagreed, and
thought that it ought to be enough to say:
void foo( float ar[n1][n2][n3][n4], int n1, int n2, int n3, int n4 )
that is, to delay the binding of n1, n2, n3 and n4 until the end of
the prototype was reached. Cray had already implemented the extension
in this way. But I believe that in the end, it was Stallman's
suggestion that was adopted. To some of us, it seemed that this
was forcing the programmer to jump through hoops in order to make
life easier for the compiler writers. But after all, this has
to be done only in the function definition and prototype; using
the function is still easy for the user.
I do prefer the Cray syntax. Assuming it isn't fatally flawed (e.g.
doesn't require look-ahead to determine whether components of expressions
in [] are typenames), I'd prefer that, since it's much easier to
read. But I think it might be fatally flawed that way. C lexers
typically need to consult symbol tables to determine whether names
are typenames, and the above syntax would seem to violate that need,
suggesting perhaps an ambiguous syntax requiring lookahead. I believe
g++ purposely implemented an incompatible rendition of a then-evolving-
standard C++ way of specifying something (`new' comes to mind?) for
a reason like this, because the g++ way made the compiler noticably
faster because of not needing to do look-ahead.
While using the function is still "easy", it isn't if the user has to
read the function declaration to understand what to do, and it's
more difficult to read than it needs to be. That is, it isn't easy
enough compared to Fortran. My thesis is that for the new features
in C to be useful, they shouldn't be much harder to use than their
equivalents in Fortran when compared to other similar feature sets.
(BTW, I'm still not certain that this is exactly what was adopted in
the end....)
Looks familiar to me.
I will state this personal experience here:
In implementing and maintaining g77, I have had to worry about adjustable
arrays. Now, I have almost _never_ written any code using adjustable
arrays in my life. It's just rarely the kind of code I write.
Further, I have written vastly more code in C than in Fortran.
However, in writing test cases for both g77 and gcc to compare how they
handle various adjustable-array situations, I found that I almost never
screwed up writing the Fortran versions, but had _major_ problems writing
the C versions. I had to edit, compile, figure out what the error
messages could mean, and redo that cycle many times to get something that
appeared to work. Further, even though I did this only a few weeks
ago, I _still_ cannot remember offhand exactly what I discovered actually
worked!!
The implication to me is that the syntax used by gcc to do function
definitions for adjustable arrays is too hard for ordinary use. And
that the C language committee people would be wise to make it
simpler, or not do it at all.
>...For example, the C equivalent of
>Fortran 90's omitted arguments could not be straightforwardly implemented
>using this extension...
Nobody said that this was supposed to provide a drop-in for arbitrary
Fortran routines, or to facilitate the translation of Fortran code
into C. The motivation was to facilitate numerical programming in C,
not mixed-language programming, and not F->C tranlation. It does, in
fact, facilitate these two things in a limited way, but nothing you've
said contradicts the assertion that it performs its stated purpose well.
I've now added some data on that above (the fact that, as a highly experienced
C coder, I had a very difficult time writing even a simple case and getting
it to compile).
I didn't claim people were going to insist on using this feature to
do drop-in replacement of Fortran. Rather, that the fact that a
_numerically_ oriented language like Fortran already significantly
improves on the flexibility offered by the proposed C extension, and
in a manner much more in line with the existing language, suggests
that the C proposal is too little, too late, and just another
technological cul-de-sac waiting to happen.
I agree with you that this is a peripheral issue, but I don't think what
you say is correct. Everything before the semi-colon is treated as
a "tentative declaration" to be pushed onto the parsing stack until
it's encountered again after the semicolon. When it's encountered
after the semicolon, it's restored to its proper position in the
prototype. In any case, commas in prototypes, or in pre-ANSI
function definitions, are quite different from commas in executable
code.
Further, as I pointed out, commas in executable code are quite different
from commas in executable code. (Compare "i = j[k,l];" with "i = j(k,l);".)
My point is that use of the proposed extension will make the C language
significantly harder to quickly visually parse by typical users.
Remember, programmers will be reading both the declarations AND the
definitions of functions, just like they do in Fortran. Having semicolons
suddenly turn into higher-precedence operators (in a sense) than commas
in a particular narrow context will be a problem.
I already have trouble reading (and certainly writing) the small examples
we've been discussing. I'm speaking as someone who has found bugs in
code written in Fortran, PL/I, and C by watching the code scroll by at
9600 baud over a period of minutes. This is an extreme case (and
capability -- no, don't ask me how I do it, I'm not sure I really
understand it) but to me it illustrates how important it is for context
to have as little impact as possible on the way text is _lexed_ and
_parsed_ (grouped and such).
Actually, I think the problem already exists in ANSI C, but I get
the impression it is rarely used or needed. Adding adjustable arrays
to C in this manner will change that, and IMO make C a much less
attractive language.
>What I'm not so sure of is whether it'll be possible to extend
>C in ways sufficiently elegant to be worthwhile to get these various
>features (especially noalias)....
It might not be; I'm not sure.
Yes, I want to point out, I'm _not_ saying these extensions cannot be
done, or that they will not be useful -- in fact, I can emphatically
state the opposite. They CAN be done and WILL be useful.
But, my concern is that either the Keepers of the C Language Flame will
reject these extensions, or will adopt them against the long-term
sensibilities of the C community, in either case dooming them (and code
that uses them) to obsolescence much sooner than the FORTRAN 77 code
for which they are trying to provide an upgrade path, in essence!
It might happen by someone later discovering the _right_ way to do the
extensions, and people switching to that by writing new code for it,
and you're left holding all the old code and needing a tool to translate
(another host of problems there, though thankfully it's getting
easier).
>... Note that already the proposed C syntax
>for adjustable arrays is much wordier than the equivalent Fortran syntax
>when compared to the simpler, non-adjustable-array example.
Yes, due only to the protests of C compiler writers. Even so, as
I mentioned, the *use* of the function is no wordier than before --
only the function definition and prototype are wordier.
This is indeed important.
You know, I wonder if a better overall solution for C would be to
kind of punt to Fortran/K&R C and allow this as a function declarator
(for either a declaration, ending in ";", or a definition, ending
in "{...}"):
void x(a, i, j) ({ int *i; int *j; float *a[*i/*j]; })
The above uses the syntax of the gcc extension for statement
expressions in a place where it wouldn't be allowed. It certainly
solves the problem of helping the lexer distinguish between kinds
of symbol names, and I think it might offer a more elegant solution
for other problems as well. Plus, it's basically as easy to read and
write as the equivalent Fortran (i.e. the delta from Fortran to C doesn't
suddenly hit a big spike when dealing with adjustable arrays). (It
doesn't solve the problem of needing to conditionalize the automatic
evaluation of dimension expressions, but perhaps makes ugly syntax
like my other proposal easier to swallow, since it's moved out of the list
of arguments.)
See, as a language designer, I look for more general extensions than
specific ones, because the latter tend to complicate the language
too much to solve too narrow a problem. Whereas, the fact that I did
it off the top of my head notwithstanding, the proposal above seems
to offer all the ability of the rms and Cray extensions without adding
anything particularly significant _except_ to borrow a syntactic lexeme
from another extension I'd like to see adopted (statement expressions).
(Not that my proposal is all that great; other people should definitely
think it through, because I certainly haven't. But offhand it seems
to offer all the cleanliness of the Cray approach and the internal
compiler elegance of the rms/gcc approach.)
>...It might not
>be worthwhile to extend C so that expressing more generality than the language
>already offers (such as a single-address-space model) can be done in
>a portable, readable way, for example, or so that expressing the notion
>of adjustable arrays can be done (since that can be coded by hand anyway).
Yes, but it's tough to do for higher-dimensional arrays, and especially
tough to write loops in an optimized or readily optimizable manner.
Agreed. Just as it's tough to do C-style things in Fortran. But I
wouldn't, as a Fortran language designer of sorts, let C programmers
tell me how to extend Fortran so they could do their tricks if the
extensions made Fortran even more a bundle of non-orthagonal extensions
than it is. I'd look for ways to include the facilities in more
general ways, and perhaps end up not adopting the proposals at all
if I were not successful.
>I wonder how much C code out there is using the gcc extension for
>adjustable arrays? ....
None of mine, but if this ever becomes part of ANSI, I'll certainly
use it.
I wonder how much Fortran code was using adjustable arrays before
F77 became official? I'd like to see some C usage on a scale like
that before ANSI adopts the gcc extension, or anything else like
that, to make C more like Fortran. I doubt a lot of Fortran programmers
waited for ANSI to bless REAL A(N) before using it.
>It might turn out that it is best to leave both languages with their
>default views of their computing universes, and suggest to people
>insisting on using one of them for the others' purpose to simply switch.
Well, as a simple programmer, C and Fortran don't seem so philosophically
different to me. My view of the programming universe is pretty much
the same when I use C and when I use Fortran. It's just that there
are some things that are easier to do in C, and some that it's easier
to do in Fortran. Incremental changes like automatic arrays for C
would help me out a lot when I have an application most of which is
ideally suited for C but some of which is ideally suited for Fortran.
It simplifies my life in many ways not to have to resort to mixed-
language applications.
But it doesn't simplify your life to offer new versions of languages
that have many more non-orthagonal features, to the point where even
visually parsing the flow of the code is made much harder. That's
what I'm suggesting is worth avoiding, even at the expense of not
offering useful new features.
>...Other such philosophical contrasts exist as well (e.g.
>Fortran's .AND. is more general and thus more optimizable than C's
>&& and &, same with .OR. vs. || and |).
How?, restricting ourselves to .AND./&& and .OR./||. I really
wish Fortran required these to be parsed left-to-right, so I
could write in Fortran:
IF( M.GT.0 .AND. A(M).NE.0 )THEN...
instead of having to resort to:
IF( M.GT.0 )THEN
IF( A(M).NE.0 )THEN...
Again, viewed pragmatically, this is just a pain in the ass, IMHO,
compared to C. But I think you have more than this in mind, and
I'd like to know what.
I agree these C features would be useful in Fortran!!
But again, as a language designer, I would have to see a
proposal that made an orthagonal and visually consistent improvement
to Fortran to offer them myself.
For example, it would _work_ (and be _useful_) to simply add && and,
since | is not part of the Fortran character set, // to Fortran to
mean their C equivalents. Sure, // has another meaning in Fortran --
character concatenation -- but within the language there isn't any
potential for ambiguity I can recall.
This to me is quite equivalent to some of the extensions we've
been discussing for C. And to me it is about as wrong-headed.
For even though it would _work_ to extend Fortran so
"IF (FOO//BAR) THEN" means C's "if (foo||bar)", it wouldn't make
sense from a language-design point of view. Programmers would soon
have more trouble reading existing code that didn't use the new features
(as I think is true of the gcc extension for adjustable arrays); they
wouldn't get the right results if they did what they're used to for
C, i.e. use a single character to get a non-sequenced test (i.e.
"IF (FOO/BAR) THEN" would not mean C's "if (foo|bar)"); they
might have trouble understanding how the new features interact with
popular existing extensions; experienced programmers not familiar
with the new features would see code using them as having serious
bugs, and probably not suspect they were using new features; etc.
I still cannot think of an elegant way to extend C for adjustable arrays --
one that is orthagonal to most of the other traditional and standard
features of the C language, like omitting arguments by passing NULL
or even just junk (when the context of the invocation is enough to
inform the called procedure to not do things like dereference its
arguments, evaluate expressions based on its operands, etc.).
But if someone comes up with something, I'd be very interested in seeing it,
since I think adjustable arrays are an important feature for C. I also
think multidimensional arrays are important as well, but unless a new
lexeme is introduced, I think C's comma "blunder" has already rendered
the success of any such effort quite unlikely. (To wit: obviously C
already specifies a meaning for "a[i,j]", so that cannot be redefined
without great pain to have a meaning a la "foo(i,j)"; yet due to the
latter using comma instead of semicolon from day one, as in "foo(i;j);",
it would be a disaster to use semicolon for dimension-expression
separation, as in "a[i;j]". Perhaps a whole new array syntax using a
new lexeme, a la gcc's statement-expression syntax and lexeme, would
work -- "a([i,j])" -- but even that will be challenging for C programmers
to quickly distinguish from a strange-looking function call. Short of
a flag day to make "a[i,j]" mean what it should, this seems insoluable
in the context of the C language.)
I keep this sort of thing in mind because this is an example of
doing something "easy" and "obvious" and "useful" in the history of
a language, that ends up interfering with future extensions that
would be even _more_ easy, obvious, and useful.
After all, had C never defined a comma operator, and instead left it
to a more involved syntax like gcc's for statement expressions --
e.g. instead of "(i=j, c=d)", we'd have "({ i=j; c=d; })" -- then
we'd be free to use the comma in C for things for which it is more
useful, like multidimensional arrays. And I suspect the compilers
would be simpler (once they implemented all the necessary extensions).
Fortran had blunders like this longer before C was even a gleam in
anyone's eye, but it did at least have the advantage of growing up
during a time when there was a dearth of characters, allowing new
features to be, on occasion, added by using new characters (":" in F77,
";" in F90, for example). C started out using more characters than
most existing programmers knew existed at the time (e.g. lower case,
braces, etc. :-), and pretty much defined them all to mean _something_,
even if that something wasn't particularly needed at that level of
expressiveness (the character/lexeme), too early.
Again, this isn't a flame of either language or the language designers.
But it is a warning that we had better learn from our history if we
do not want it repeated, and especially if we do not want future semi-
washed masses criticizing us the way many today do criticize the
"ghods" who gave us Fortran and C -- who, by the way, were dealing
with vastly more challenging problems than we are while trying
to design languages, not to mention not having the collective linguistic
experience we now have.
Array boundaries could (and should, IMHO) be restricted to (constant?)
integral lvalues.
void foo( const int n1, const int n2, const int n3, float ar[n1][n2][n3]) {
}
(which should also make the compiler's job easier ;-)
No. That would make it even more unnecessarily restrictive than the
current proposed (gcc) syntax, and certainly lots of Fortran code wouldn't
be easy to port to such a restrictive environment.
Passing 0 as an array dimension would signal this clearly enough,
I think.
Again, no, it'd signal an empty array, and in any case as I said above,
the caller isn't passing an array dimension, rather an array along with
other info, and it's up to the function definition to decide how to
express the dimensions of the array using that other info (plus things
like info in global and static storage, a la Fortran's REAL A(N)
when N is in COMMON).
I don't think there is a real need, in C, for being able to
specify array bounds as expressions; the programmer can take care
of that.
Not when the programmer is the user of a library, as happens in Fortran.
Yes, it's less elegant than the Fortran version, but it would be a BIG
win over what's currently available in C.
Not big enough to be worthwhile IMO.
Hmm... just wondering... what should the syntax to the eqivalent
of an ALLOCATABLE array look like? Do we finally get a pointer
to an array as being different from the first element of
an array? :-)
Not sure offhand what you're asking...but IMO C has an advantage here
over Fortran in that "foo(a[1]);" vs. "foo(&a[1]);" expresses a
useful distinction that cannot be expressed in Fortran -- since
"CALL FOO(A(1))" does not specify whether a single element or an
array is being passed. I don't think it's a major difference, but
I'm right in the middle of writing new code in g77 that has to
take into account the ambiguity and thus produce slightly slower code
for cases that, most of the time, would work using the slightly faster
code. ("CALL FOO((A(1)))" is a work-around, but not if the argument
is defined by FOO.)
[Lots of stuff deleted]
>A very childish warrior, I'd say!. Again many of your people are
>still are using F66 insternally! Does IMSL 90 or NAG 90 available?
^^^^^^
Yes. Check http://www.nag.co.uk/
--
Peter Marksteiner
Vienna University Computer Center
Universitaetsstrasse 7
A-1010 Vienna, Austria
e-mail: Marks...@cc.univie.ac.at
Tel: (+43 1) 406 58 22 255
FAX: (+43 1) 406 58 22 170
Theoretically yes, but practically no.
No need for further explanation for such shallow attack.
Shame, shame...
Woon-Chul Choi
He was merely pointing that there is a way to do that.
And at least he did contribute something you obvously don't know.
What is your purpose of posting?
Who are you?
A typical flamer....
As I said before, if you have nothing to contribute, shu.....
Woon-Chul Choi
Oops! You got me here. Well, it is OK, because I didn't intend to
teach him, but just tried to show the way in C.
> Either way you are, IMO, hacking normal code into abnormal
>code to increase performance, a required evil at times but something
>to be avoided when at all possible. Why stop there? You did not
>collapse the loops as well, as in:
I would admire your imagination. Creating comfortable circumstance
for you to attack someone.... Good move...
> Save the stupid multiplications and insure that even the dumbest
>compiler (oops, an absolute, most compilers?) can see you are indexing
>sequential memory locations and optimize based on that. Most real numerical
>codes don't give a squat about outputting indexes until the bitter end,
>so I ignored that in your example.
You don't get it, do you? I was merely pointing that there is way to
do in C. Also, the purpose of most example is to emphasize a certain
subject. Anyone who is confused with or take it seriously is surely a
candidate for ( ) <--- I will leave it blank. Fill whatever you like.
With your imagination, you can do it. I believe you, Tom.
You may be surprised that if I tell you where I learned those stupid
things from. I learned it while doing tralslating LSODE, the most
widely used stiff ODE's solver.
> WHAT, thats "ugly" and hard to understand you say? Using clever #define
>just sweeps the "ugly" details under the rug, so to speak. What happens
>when you have 500 different such arrays in a non-toy problem, 500 #defines?
As I said before on different posting. Theoretically yes, but practically
no. You should know that, since you seem a smart guy. For the record, I
used only one (read my lips, 'only one') and affect on three lines in CLSODE,
not even in CLSODE itself, but rather in an example program.
Well, if you still wander between theoretical world and practical world,
try to reduce the intensity of your daydream. Hitting your head with a
hammer will do the job. -:)
>Would you really appreciate using a debugger on highly pre-processed code?
>I wouldn't. My point, a HACK is a HACK, no matter how much sugar you
>put on it to disguise its bitter taste. Using 1D arithmetic to show
>the efficiency of (2+)D arithmetic is pointless. Work-arounds almost always
>makes code more difficult to maintain, more bug prone, difficult for
>others to use, etc, but they are needed some times.
"... is pointless..... but they are needed some times."
What? You didn't wake up yet? Hello Tom, hello....? Where are you now?
>Be a real programmer,
>admit your HACKing, comment the hell out of it and be able to defend
>why you HACKed your code.
I like your attitude. But I don't have a space for commenting on my
obfuscated C source. Since you are claiming a real hacker, tell me.
Where should I put the comment in my obfuscated code? Better yet,
do you think it is worth to put comment statment in obfuscated code?
Anyway, yup, be a one, don't dodge.
>HACKer Tom
Woon-Chul Choi
---------------
Not qualified to be a hacker yet. Though trying very hard to be a
hacker and flamer.
Another wanderer.
Is this **.gov address for the daydreamers? -:)
Wake up, man.
I was talking about readability compared to f2c'ed source.
You can see fortran's xxx(i,j,k), but not c's xxx(i,j,k)?
What if I use C++'s object xxx(i,j,k)?
I am sure you still don't understand it.
Not because it is a kludge, but because you decide not to see it.
Get it?
Anyway, I wasn't attack your religion (Fortran. Who is your leader?).
I had no intention to start holy war, and you may be a crusader,
but I certainly am not a cult member. If I am one of them, I
already cross-posted my previous posts on comp.lang.c to get
help from there.
They could squeeze you. -:)
>Fortran code from the '60s looked like
>this too, and that is presumably why C was designed this way. However, by
>the mid '70s fortran compilers generally treated multi-dimensional arrays
>correctly, and this kind of kludge was no longer necessary (in fortran
>that is).
You are correct. I used this kind of kludge while translating your
legacy (an old Fortran code).
It is called LSODE (ODEPACK).
So, do your Fortran guys translted LSODE to F90 (of F95) yet?
Please don't tell you didn't.
What? No?
How comes!
How come you guys still using those stupid old kludges?
It is really shame, isn't it?
Seriously, visit netlib.
Some of them are still using Hollerith format.
Although you don't have to use that kind of kludge anymore on interface,
deep in the libraries, they are still there. They are there
waiting for you.
Get it?
>
>However, in f77, the standard defined a more generalized array declaration:
>
> dimension a(ilow:ihi, jlow:jhi, klow:khi, llow,lhi)
>
>for example for a 4-d array. All ranges are integer variables (not
>constants). I'd be interested in seeing a C macro that makes this kind of
>generalized array expression comprable to fortran
>
> a(i,j,k,l) = ...
>
Who care?
But don't assume naively that Fortran doesn't do such arithemtic
internally.
Next time, are you gonna ask me macro defintion for 5-d array,
if I give you 4-d now?
>And if you come up with one, try to convince me that it is simple enough
>to optimize by the compiler, and to maintain by the programmer (or by
>several programmers).
Try to convince you??? You believe one can covert a cult member
(like you) back??? You should be at Waco, Texas two years ago.
You could save the many precious.
>Once you've done this, you can say that C is
>comparable to f77 (an 18 year old language). Then we'll show you what f90
>can do! ;-)
>
A very childish warrior, I'd say!. Again many of your people are
still are using F66 insternally! Does IMSL 90 or NAG 90 available?
How many package at netlib is written in F90?
Get it?
>Oh yeah, and don't forget in these macro definitions that division in C
>involving negative integers is not well defined, so you must account for
>the possibility that your machine rounds the unexpected way.
>
>>Shallow, shallow....
>
>Sort of like that post a few weeks ago that claimed complex exponentials
>had no meaning, so it was useless for a language to allow them. ;-)
>
>$.02 -Ron Shepard
If you haven't got it yet, hit your head very hard with a hammer. -:)
Get it?
Woon-Chul Choi
< Lots of flames deleted. >
>A very childish warrior, I'd say!. Again many of your people are
>still are using F66 insternally! Does IMSL 90 or NAG 90 available?
>
>Woon-Chul Choi
>
Yes. The NAG Fortran 90 library is available. I believe it has been completely
rewritten and does not use any of the old stuff internally.
--
Ronald Sverdlove Computational Science Research
r...@sarnoff.com David Sarnoff Research Center
Tel. 609-734-2517 CN 5300
FAX 609-734-2662 Princeton, NJ 08543-5300
>>...Other such philosophical contrasts exist as well (e.g.
>>Fortran's .AND. is more general and thus more optimizable than C's
>>&& and &, same with .OR. vs. || and |).
>How?, restricting ourselves to .AND./&& and .OR./||. I really
>wish Fortran required these to be parsed left-to-right, so I
>could write in Fortran:
> IF( M.GT.0 .AND. A(M).NE.0 )THEN...
>instead of having to resort to:
> IF( M.GT.0 )THEN
> IF( A(M).NE.0 )THEN...
On a related note, I once was annoyed to have to write two Block IF
statements to code something similar and tried instead (to use Peter's
example)
IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
which was rejected as illegal by all the compilers I tried. If it were
legal, it would not be completely equivalent to
IF( M.GT.0 .AND. A(M).NE.0 )THEN...
interpreted from left to right that Peter Shenkin would have liked
(since the ELSE part would not apply to the condition on M, but only on
the condition on A(M)), but I think it could be really useful sometimes
and has the definite advantage that it is interpreted from left to
right. Does anybody know why it is illegal ? Is there anything I
missed ?
--
Michel Beland bel...@CERCA.UMontreal.CA
professionnel de recherche tel: (514)369-5223 fax: (514)369-3880
CERCA (CEntre de Recherche en Calcul Applique)
5160, boul. Decarie, bureau 400, Montreal (Quebec), Canada, H3X 2H9
<big ``snip, snip''>
>I wonder how much Fortran code was using adjustable arrays before
>F77 became official? I'd like to see some C usage on a scale like
>that before ANSI adopts the gcc extension, or anything else like
>that, to make C more like Fortran. I doubt a lot of Fortran programmers
>waited for ANSI to bless REAL A(N) before using it.
Adjustable arrays (to be pedantic, ``adjustable array bounds'')
in Fortran long predate Fortran-77. They were already in the
Fortran-66 standard., and I suspect they were not a new feature
then.
(Trivia question: was the Fortran-66 standard the first
official Fortran standard? If not, what standards preceded it?)
What Fortran-77 added was syntax for *assumed-size* arrays.
In the example:
SUBROUTINE SUB( A, B, C, D, N, M )
INTEGER N, M
REAL A( N, M ), B( N, * ), C( N ), D( * )
.....
the appearances of N and M in the REAL statement are adjustable
array bounds, while the ``*''s identify B and D as assumed-size.
Fortran-77 also extended the class of allowable adjustable
array bound expressions: Fortran-66 allowed only (scalar integer)
arguments, (or variables in COMMON?), while Fortran-77 allowed
expressions as well.
Note that all versions of Fortran -- -66, -77, and -90 --
require(d) that the dimensions be evaluatable *before* the
first executable statement in the subroutine is executed.
As Craig pointed out, the syntax for adjustable (and
assumed-size, and now assumed-shape) arrays in Fortran
is an obvious extension of the syntax for fixed-dimension
arrays, and I seriously doubt that there was any argument
about it. (What sort of expressions to allow *was* probably
argued about.) This contrasts with C, where there is apparently
no obvious One Right Way to express adjustable-dimension arrays.
Two minor issues w.r.t. the C proposal, discussed by Craig and
others in other articles:
(1) There was mention of what to do if an argument
specifying a dimension is ``omitted'': this does not arise
in Fortran-77, as there are no omitted arguments. As for
Fortran-90: off the top of my head, I would guess that an
argument used in an array bounds expression can not be
declared ``OPTIONAL''.
(2) I am surprised that the proposals for adjustable
arrays in C pass the array dimensions by reference. I would
have thought they would be passed by value, since there is no
reason to allow them to be redefined.
--
Alan McKenney E-mail: mcke...@cims.nyu.edu (INTERNET)
Courant Institute,NYU,USA ...!cmcl2!cims.nyu.edu!mckenney (UUCP)
I said it was the "obvious C rendition", not that it would work!
;-)
(I think this is another point in Fortran's favor....)
In article <BURLEY.95J...@apple-gunkies.gnu.ai.mit.edu>,
Craig Burley <bur...@gnu.ai.mit.edu> wrote:
>In article <3rn3io$i...@sol.ctr.columbia.edu> she...@still3.chem.columbia.edu (Peter Shenkin) writes:
>
> All the proposals I'm aware of, and specifically, both the
> Cray and the Stallman proposal, specify passing the array dimensions
> by value.
>
>I haven't seen the proposals. I do know gcc does not prevent passing
>the array dimensions by reference. Specifically, I'm unaware of any
>particular restrictions on the expressions themselves, which is really
>what you're talking about.
To hopefully finesse this sub-issue, no, the proposals I've seen (but
may not remember exactly) do not place restrictions on how C is to
pass the array dimensions for automatic arrays. I should have said
that "the most straightforward examples involve passing the dimensions
by value."
What I meant was that, contrary to what seemed to be the impression
of the NYU guy, the values are not required to be passed by
reference. They aren't required to be passed by value, either.
I shouldn't have used the word "specify". Sorry. My fault. Mea Culpa.
Etc.
I also agree, with Craig, that features should be added in as universal
manner as possible, and that artificial resrictions are a Bad Thing.
The reason the ANSI C committee decided not to take up this issue
is that they thought there could be hidden incompatibilities. I
think the questions that have been raised here, such as how this
proposal interacts with sizeof() and with passing array dimensions
through indirection, are exactly what is needed to uncover such
incompatibilities, if any.
Yet another question is how this feature interacts with stdargs;
what would the function prototype look like if the array and its
dimensions all came, in the call, after the ellipses in the
prototype and definition? (Heh, heh.)
>(2) I am surprised that the proposals for adjustable
> arrays in C pass the array dimensions by reference. I would
> have thought they would be passed by value, since there is no
> reason to allow them to be redefined.
All the proposals I'm aware of, and specifically, both the
Cray and the Stallman proposal, specify passing the array dimensions
by value.
Perhaps your idea that they pass them by reference comes from
Craig's example, in which he tries to devise something wierd
that ought to work by the standard rules of C syntax/semantics, but
which might be problematical for automatic arrays.
In article <beland.8...@rimbaud.cerca.umontreal.ca>,
Michel Beland <bel...@CERCA.UMontreal.CA> wrote:
...
> IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
>
>which was rejected as illegal by all the compilers I tried...
>.... Does anybody know why it is illegal ?
It's illegal because X3.9-1978 says, in Section 11.5, that the
statement that follows a logical IF can be "anything except
a DO, block IF, ELSE IF, ELSE, END IF, END or another logical IF
statement."
All the proposals I'm aware of, and specifically, both the
Cray and the Stallman proposal, specify passing the array dimensions
by value.
I haven't seen the proposals. I do know gcc does not prevent passing
the array dimensions by reference. Specifically, I'm unaware of any
particular restrictions on the expressions themselves, which is really
what you're talking about.
Perhaps your idea that they pass them by reference comes from
Craig's example, in which he tries to devise something wierd
that ought to work by the standard rules of C syntax/semantics, but
which might be problematical for automatic arrays.
May be weird, but then why does Fortran permit it, and why do people
use this feature, as in
SUBROUTINE X(A,N)
REAL A(N)
...
N = 5
...
END
??
If you are certain that the Cray and/or rms proposals actually
specify a _restricted_ form of expression to be used in dummy
array dimensions -- say, not allowing indirection (the unary *) --
then I can see where you're coming from.
But, again, I see dangers in introducing to C more restricted
forms of expressions a la Fortran, in that the language is
made unnecessarily more complex -- to provide a feature that
Fortran had before F77, but with less flexibility than is
actually _used_ in F77 code (and much less flexibility than
is used in F90 code).
Reminds me of the Fortran 90 misfeature that prevents allocation
of scalars -- allowing only arrays. Thus forcing people who
want to dynamically allocate a CHARACTER*2048 to use an array
instead. (Whether a type with a length should have been
introduced in F77 in the first place is yet another question, or
example of this -- perhaps that's from where this problem stems.
I guess F95 or some future thing is considering dropping more
of the *len functionality, forcing people to move to using arrays
instead, which would have been better in the first place perhaps.)
I see this tendency to narrowly specify new extensions just to get
them working all the time. It has increased lately, now that more
people have access/ability to influence language design, e.g. by
adding features to compilers. I hope people who find the task
of conceiving and implementing such extensions not only avail
themselves of the concrete experience of the past, but the easy access
they have to experience of language designers on USENET before
making a hasty decision with potentially great costs. (Think of
new, poorly thought out language extensions in terms of new
federal regulations, and ask yourself what you think of _them_.
And remember that, for all intents and purposes, I earn my living
thanks to wrong decisions made in the past -- if the right
decisions had been made in most or all of those past cases, I'd
probably not be working on compiler development at all, either doing
end-user applications or doing work on much more advanced optimization
techniques than we have today, thanks to not having to spend so much
time reimplementing code to handle the dizzying combinations of wrong
design decisions made in the past. Again, not to insult people who
made them, but to indicate we need to learn from their mistakes --
something I gather _they've_ already done.)
>The other thing f77 added was the LOWER:UPPER bound syntax. Is there any
>movement in the C standardization to get beyond 0-based arrays? I find
>this flexibility quite useful in fortran, so I wonder why there is no one
>kicking and screaming about this in the C discussions?
Because most C programmers would find it confusing. Keeping track of
of the lower bound of every array index is a royal pain. But I'm sure
the authors of "Numerical Recipes" would appreciate it :-)
OTOH, it won't fit on the C syntax at all: *(a + i) and a[i] are
guaranteed to be equivalent, whether "a" is an array or a pointer.
With your proposal, a[i] would be equivalent to *(a + i - lower_bound).
And if you pass an array to a function, how do you pass the lower bound
information? Only by changing the semantics of C pointers into something
similar to F90 pointers. I'm affraid nobody in the C standardization
committee would accept it. Neither would I :-)
Dan
--
Dan Pop
CERN, CN Division
Email: Dan...@mail.cern.ch
Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland
>she...@still3.chem.columbia.edu (Peter Shenkin) writes:
>
>>[[ comp.lang.c removed from Newsgroups: ]]
>
>>In article <beland.8...@rimbaud.cerca.umontreal.ca>,
>>Michel Beland <bel...@CERCA.UMontreal.CA> wrote:
>>...
>>> IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
>>>
>>>which was rejected as illegal by all the compilers I tried...
>>>.... Does anybody know why it is illegal ?
>
>>It's illegal because X3.9-1978 says, in Section 11.5, that the
>>statement that follows a logical IF can be "anything except
>>a DO, block IF, ELSE IF, ELSE, END IF, END or another logical IF
>>statement."
>
>Sigh... I already know that. But why is this restriction in the
>standard in the first place ? This seems to me to be an unnecessary
>restriction.
A cleaner solution than allowing that construct would be to change the
.AND. operator semantics, so that it behaves like its C counterpart, &&,
which guarantees left to right evaluation of its arguments and short
circuiting (the evaluation stops when the result is known). This would
allow writing:
IF( M.GT.0 .AND. A(M).NE.0 )THEN...
If M.GT.0 is false, the evaluation stops immediately because the result
of the entire expression is false.
Of course, you can't do this with the .AND. operator, the way it is
defined right now.
>The other thing f77 added was the LOWER:UPPER bound syntax. Is there any
>movement in the C standardization to get beyond 0-based arrays? I find
>this flexibility quite useful in fortran, so I wonder why there is no one
>kicking and screaming about this in the C discussions?
Well, to be honest, of all the features to which the term "syntactic
sugar" can be applied, this is the best candidate, IMHO. I don't mind
sugar, and I use the feature in Fortran, but if it were missing my
response would be a shrug of the shoulders, rather than a kick or
a scream.
I even use this feature in C! How?
index_origin = 1 /* make arrays go from 1 to n */
ijk = ( int * )malloc( n * sizeof int );
ijk -= index_origin;
The comp.lang.c FAQ points out that this is not guaranteed to be
standard-conforming, however. If you want to know why, read the
FAQ. Thinking about it, I'm not sure it's right, actually.
Be this as it may, it's unlikely to fail. The same thing can
be done with statically declared arrays, as follows:
int index_origin = 1;
int ijk_dummy[ IJK_SIZE ];
int *ijk = ijk_dummy - index_origin;
for( i=1; i<=IJK_SIZE; ++i ) {
ijk[ i ] = <whatever>;
>In article <BURLEY.95J...@apple-gunkies.gnu.ai.mit.edu>
bur...@gnu.ai.mit.edu (Craig Burley) writes:
>
> <big ``snip, snip''>
>
>>I wonder how much Fortran code was using adjustable arrays before
>>F77 became official? I'd like to see some C usage on a scale like
>>that before ANSI adopts the gcc extension, or anything else like
>>that, to make C more like Fortran. I doubt a lot of Fortran programmers
>>waited for ANSI to bless REAL A(N) before using it.
>
> Adjustable arrays (to be pedantic, ``adjustable array bounds'')
>in Fortran long predate Fortran-77. They were already in the
>Fortran-66 standard., and I suspect they were not a new feature
>then.
>
> (Trivia question: was the Fortran-66 standard the first
> official Fortran standard? If not, what standards preceded it?)
Yes, I think it was the first fortran standard. But it wasn't ANSI was
it; there was some other standards organization, ASA or ASI or NSI or
something like that before ANSI? I believe I've read that it was the first
programming language standard.
>What Fortran-77 added was syntax for *assumed-size* arrays.
[...]
Of course, the older convention was to use A(1), B(N,1), and so on for
this functionality.
The other thing f77 added was the LOWER:UPPER bound syntax. Is there any
movement in the C standardization to get beyond 0-based arrays? I find
this flexibility quite useful in fortran, so I wonder why there is no one
kicking and screaming about this in the C discussions?
$.02 -Ron Shepard
ASA probably (American Standards Association). It became ANSI in one of
those numerous name changes. There has as far as I know only been one
US standard institutes, although it has had a lot of different names.
Before that time there were Fortran standards, but they were company
standards rather than national standards (let alone international
standards). I do not know whether it is the first programming language
standard, it might be. But I know there exists:
DIN-Norm 66 006, Informationsverarbeitung, Darstellung von ALGOL-Symbolen
auf 5-Spur-Lochstreifen und 80 spaltigen Lochkarten
from Juni 1965 or earlier. That is something Fortran can not clain: a
standard specifying how to represent Fortran symbols on 5 track papertape.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924098
home: bovenover 215, 1025 jn amsterdam, nederland; e-mail: d...@cwi.nl
>[[ comp.lang.c removed from Newsgroups: ]]
>In article <beland.8...@rimbaud.cerca.umontreal.ca>,
>Michel Beland <bel...@CERCA.UMontreal.CA> wrote:
>...
>> IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
>>
>>which was rejected as illegal by all the compilers I tried...
>>.... Does anybody know why it is illegal ?
>It's illegal because X3.9-1978 says, in Section 11.5, that the
>statement that follows a logical IF can be "anything except
>a DO, block IF, ELSE IF, ELSE, END IF, END or another logical IF
>statement."
Sigh... I already know that. But why is this restriction in the
standard in the first place ? This seems to me to be an unnecessary
restriction.
--
Be this as it may, it's unlikely to fail. The same thing can
be done with statically declared arrays, as follows:
int index_origin = 1;
int ijk_dummy[ IJK_SIZE ];
int *ijk = ijk_dummy - index_origin;
for( i=1; i<=IJK_SIZE; ++i ) {
ijk[ i ] = <whatever>;
}
It can fail on systems where subtracting, and then adding, a particular
value to a pointer does not result in the original pointer. I _think_
some segmented systems are this way, but frankly after being able
to ignore such systems for many years now, I can't remember whether
it's ever a real problem.
Note that it can invite strange bugs. E.g.:
p = malloc(...);
p -= offset;
...use p...
free(p); /* Should have been free(p+offset). */
The free call might appear to work, but you're basically screwed after
that.... :-)
Not to mention the unexpected interactions with testing an offset pointer
for NULL (or accidentally offsetting a NULL pointer)....
It really is a major challenge to try and put the kind of "natural"
arrayness Fortran has into C. I hadn't even thought about the
low-bound issue, but it's another example of something I think that
can trip up, long-term, any attempt to extend C to encompass the
numerical orientation of Fortran. Going to a whole new array
notation for the new stuff, as in `float a([0:10]);' or
maybe `float a[[0:10]]' -- something that distinguishes the
new set of array features from the old -- _might_ make it work.
I believe it would be at least necessary to do so, but it might not
be sufficient. (The new notation would make it immediately clear,
for example, that g[[i]] is _not_ the same as *(g+i), and that, in
fact, the latter might well be invalid code.)
I'm trying to thinks of things going in the other direction.
E.g. what would be _useful_ and _elegant_ to bring into Fortran
about C's notion of sequence points in expression?
I have a gut feel that extending expressions themselves to include
sequence points is going to be a miserable failure. The mindset
that need not worry about expressions being mini-programs is a
hard one to reeducate, especially when it isn't necessary. (And
this mindset is possessed not only by most Fortran programmers, it's
the classic mathematics mindset, so I suggest it's a big win to
continue to allow people with this mindset to easily understand
Fortran code. It even makes it easier for compiler developers like
me to think about their work, I believe.)
Some extensions I think might be worth thinking about:
IF (expr) THEN
...
ELSE AFTER
...statements setting up next test...
THEN IF (expr)
...
END IF
That is, in place of an ELSE IF (expr), where one wants to preface
expr with setup statements (in C, "else if (stmt, stmt, expr)" or,
in gcc, "else if (({stmt; stmt; expr}))"), one uses ELSE AFTER/THEN IF.
So, that is a step in solving one problem I've had and seen other
people report when it comes to writing clean structured Fortran
(really it just saves using extra levels of IF THEN/END IF).
E.g. making subroutine calls that perform side effects, and then
testing the results of those subroutine calls. (One could even
claim it would be most elegant to allow an initial "AFTER" followed
by setup statements to precede an IF THEN. Then the compiler
would be allowed to not execute those setup statements if it could
determine that the IF would be false anyway. Or, just execute
them as if the AFTER wasn't present. Meanwhile, disallowing jumping
to any labels on the first statement after an AFTER (or ELSE AFTER,
but I think these are already disallowed) through the corresponding
IF THEN might be smart, unless done from within that block.)
But while the above might be interesting (and probably easy to add to
g77 to try it out), there's a larger issue here. Is it really worthwhile
to find ways to move all the useful C operators (like the sequencing
ones -- , && || =) into Fortran even if it can be done in a way that
is comfortable to Fortran programmers?
I don't know the answers to the above questions. I do know that
as a language designer, I'd feel much more comfortable adding the
extension I proposed above, plus whatever others like it are needed
to round out the language, than doing (what I am pretty sure would,
in g77, be) the much easier task of adding new operators for
sequencing expressions, doing assignments, etc. a la C. I'd
be more comfortable because while the latter would be easier and
make C programmers more comfortable with Fortran, they'd make Fortran
programmers much less comfortable with the resulting language (and
code written by C programmers). To the extent C programmers even
bothered really switching, they'd write C in Fortran, whereas the
former approach would encourage them to write Fortran in Fortran
(it'd be hard to do otherwise).
Since I am very interested in designing new, practical languages and
their toolsets, I like to think about these issues a lot. Sorry
if I get a bit too enthusiastic over things that probably won't
(or shouldn't) ever happen. :-)
Yes. This is the reason the code may not be standard conforming.
For instance, if on some architecture "1" is a valid pointer address,
and malloc() returns 1, and the index-origin is 1, then all references
to ijk in the for-loop are obtained by indirection through an offset
NULL pointer. This is a no-no.
>Note that it can invite strange bugs. E.g.:
>
> p = malloc(...);
> p -= offset;
> ...use p...
> free(p); /* Should have been free(p+offset). */
>
>The free call might appear to work, but you're basically screwed after
>that.... :-)
Right. You had better not do this! You must free( p+offset ).
>Not to mention the unexpected interactions with testing an offset pointer
>for NULL ....
Right. For instance, you'd better test for a NULL return from malloc
*before* offsetting the pointer. But once you're using the pointer
as an array, and an array only, you don't have to worry about this
any more.
Craig comments further about the difficulties of introducing true
"arrayness" into C. Some folks, likewise, regret the introduction
of the POINTER concept into Fortran.
Instead of a "pointer" concept, one can think of it as a "runtime
equivalence". It is easier to understand, and to explain to others, this
way, and it is not so easily confused with a C-style pointer. Of course,
after EQUIVALENCE is removed from the language and no longer used, we
won't have this crutch any more. ;-)
$.02 -Ron Shepard
D> The idea is that in order to access an element of a 4 dimensional array
> in C you need 4 memory accesses, while in Fortran 1 is enough. Quite a
> difference and memory accesses tend to be expensive on most RISC
> systems.
I don't want to continue this thread forever, but:
it is my experience with 2-D arrays that the difference is often
much less than the theory would suggest. Sometimes when the elements
are not accessed sequentially, the heavy integer multiplication penalty
implicit in finding the addresses of static arrays counterbalances the
smaller amount of pointer loads.
Let's keep it clear that the 4 memory access penalty only occurs
for arrays declared (e.g.) double ****a. A C array declared as
a[J][K][L][M] will still require 1 pointer load per element, just
like fortran. I'm curious now, though; how are dynamic arrays in
F90 addressed at the assembly language level?
---
ÅŸ SPEED 1.40 #1564 ÅŸ
--
The Albuquerque ROS - (505) 296-3000
Consider the case where a routine needs auxiliary storage. In
Fortran 77, you'd probably pass it along with the other arguments;
in Fortran 90, you'd use an ALLOCATABLE array.
The typical C way of doing things would be to allocate memory
with malloc() and then use this, as in:
void foo(double *a, const int n)
{
double *b;
b = malloc(sizeof(*b)*n*n);
[... use b]
}
Now, how could I best access b as if it were an n*n array?
Should it be possible to declare a 'temporary' array, as in
double **b;
b = malloc(sizeof(double)*n*n);
{
double b_array[n][n] = b;
}
?
--
Thomas Koenig, Thomas...@ciw.uni-karlsruhe.de, ig...@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.
>Let's keep it clear that the 4 memory access penalty only occurs
>for arrays declared (e.g.) double ****a. A C array declared as
>a[J][K][L][M] will still require 1 pointer load per element, just
>like fortran.
Let's keep it clear that such an array cannot be passed to another
function, if the dimensions aren't known at compile time. If you want
to use the syntax a[J][K][L][M], your _only_ chance is to pass a
double ****.
>I'm curious now, though; how are dynamic arrays in
>F90 addressed at the assembly language level?
Unlike the sizes of the dynamic C arrays, the sizes of the F90 dynamic
arrays are transparently passed to any routine which needs them, so the
same kind of index arithmetic can be performed as in the case of statically
dimensioned arrays. In both cases (dynamic and static) the array sizes
are likely to be stored in registers (as long as possible), for
performance reasons.
> IF( M.GT.0 .AND. A(M).NE.0 )THEN...
>Of course, you can't do this with the .AND. operator, the way it is
>defined right now.
And of course it is completely out of the question to change the semantics
of .AND. itself. What one could easily do is introduce a new operator.
(Call it .AND_THEN. by analogy with Ada's "and then"; there could also
be an .OR_ELSE.)
Unfortunately, this is precisely the sort of thing you can't do with
the current INTERFACE OPERATOR(.AND_THEN.), since that actually invokes
a function with two INTENT(IN) arguments, and both operands would have to
be evaluated before the call.
Note that while it may be slightly more cumbersone to code
IF (M.GT.0) THEN; IF (A(M).NE.0) THEN
!...
ENDIF; ENDIF
the language does allow you to do it. That makes additions such as
.AND_THEN. and .OR_ELSE. less absolutely necessary. They'd be nice
to have, but we can live without them.
--
Sergio Gelato <gel...@sissa.it>
Craig comments further about the difficulties of introducing true
"arrayness" into C. Some folks, likewise, regret the introduction
of the POINTER concept into Fortran.
I'm hesitant to agree with the regret, not really having more than
a shallow understanding yet of the F90 feature set, including
POINTER.
One thing I will say for POINTER as added to F90 -- it doesn't appear
to be even close to an attempt to add C's pointer facility. It basically
doesn't intrude in expressions at all (in that expressions don't
suddenly take on a vast new dimension that Fortran programmers don't
generally expect), and has nowhere near the low-level flexibility as
C's pointer facility.
I'm not sure whether that's good or bad, but in line with my other
meandering posts, I'd tend to think it's probably more likely to succeed
than would introducing a C-type pointer facility to Fortran, e.g. one
where one could tersely and concisely express, in Fortran, C constructs
such as:
char *p = ...;
char *q = p;
while (*p != *q)
++q;
i = q - p;
...
Fortran has what I consider to be a fairly nice division between
statements and expressions that, in C, is becoming increasingly
hard to make: expressions are about calculating results, possibly
regardless of any side effects, and statements are about specifying
side effects and sequencing (ordering).
It's nice that, while F90 trounced on some classic Fortran principles
that I thought were also quite worthwhile, it didn't trounce on this
one (again, as far as I can tell, not having really studied the F90
standard in a long time) in adding POINTER. And of course it added
TARGET as well to try (unsuccessfully?) to avoid making use (and even
nonuse?) of POINTER necessarily force contemporary compilers to generate
much less optimal code because of aliasing possibilities.
One could similarly say it is nice that C doesn't make "unnatural"
distinctions between array and pointer arithmetic, and potentially
upsetting that this might change to make C more attractive to
Fortran users.
Why? Why invent such an unreadable syntax. (Of course, what is unreadable to
one, is perfectly natural to another.)
As long as you _are_ defining arrays with non-constant dimensions, you might
as well choose the obvious
double (*b)[n] = malloc(n*sizeof(double[n]));
/* Allocate space for n arrays of n doubles and assign the pointer to b
after converting to the correct type: the correct type being a pointer to
an array of n doubles */
which is almost exactly like double b[n][n] except for bounds checking: but
then C traditionally offers no help to a compiler which wants to do bounds
checking on a malloc'ed array anyway.
As an aside, a smart compiler should also notice that b has been malloc'ed
and so *(b+expr) cannot be an alias for (expr_not_involving_b) till any
pointer is assigned to from b. (malloc cannot legally be the name of a user
routine). I do not remember seeing a compiler that does this kind of
optimization though.
Cheers
Tanmoy
--
tan...@qcd.lanl.gov(128.165.23.46) DECNET: BETA::"tan...@lanl.gov"(1.218=1242)
Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87544-0285,USA H:#3,802,9 St,NM87545
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003 voice: 1 (505) 665 4733 [ Home: 1 (505) 662 5596 ]
>|> Now, how could I best access b as if it were an n*n array?
>|>
>|> Should it be possible to declare a 'temporary' array, as in
>|>
>|> double **b;
>|> b = malloc(sizeof(double)*n*n);
>|> {
>|> double b_array[n][n] = b;
>|> }
>Why? Why invent such an unreadable syntax. (Of course, what is unreadable to
>one, is perfectly natural to another.)
Because I want to access array elements with constant memory stride.
This has been discussed on c.l.f and c.l.c just recently. The only way to
get the intended effect right now is via
b[n*i+j]
(which is what f2c does). C definitely lacks a good matrix data type; there
are about 10 ways to get it half right.
My suggestion was the currently illegal
double (*b)[n] = malloc(sizeof(double[n]));
Why do you think this involves a variable stride?
(Actually when you write b[i][j] after declaring it b[m][n], it is exactly
the same as
*( (double*) &*( (double(*)[n])&*(b+0) + i) + j)
Where I have put in the redundant casts to show why my syntax is identical to
what you wrote. Also notice that the &* and the +0 are there to enforce the
syntax rules: they involve no computation.
If the above notation is obscure, let me point out that with both
double b[m][n]
and
double (*b)[n]
b[i][j], if valid, is same as *(double*)((char*)b + (i*n+j)*sizeof(double)), if
valid. There is no difference between the two in the striding. I think you
are confusing my suggestion with double **b, which indeed is a different
matter.
|>
|> This has been discussed on c.l.f and c.l.c just recently. The only way to
Nothing to the contrary has been posted in comp.lang.c (I read
comp.lang.fortran sometimes, and haven't seen anything there either.) The
problem is that C does not allow _variable_ dimensioning. That is not at all
the same thing as inventing a new syntax where an array can be initialized
from a pointer (your suggestion). In fact, allowing it, is both unnecessary
(as I pointed out) and without enough care, will make the grammar hopelessly
ambiguous.
|> get the intended effect right now is via
|>
|> b[n*i+j]
|>
|> (which is what f2c does). C definitely lacks a good matrix data type;
there
|> are about 10 ways to get it half right.
The reason, as I said, is absence of the type `double[n]' with n a
non-constant expression: not two dimensional arrays initialized by pointers.
>In article <danpop.803216421@rscernix>, Dan Pop <Dan...@mail.cern.ch> wrote:
>>A cleaner solution than allowing that construct would be to change the
>>.AND. operator semantics, so that it behaves like its C counterpart, &&,
>>which guarantees left to right evaluation of its arguments and short
>>circuiting (the evaluation stops when the result is known). This would
>>allow writing:
>
>> IF( M.GT.0 .AND. A(M).NE.0 )THEN...
>
>>Of course, you can't do this with the .AND. operator, the way it is
>>defined right now.
>
>And of course it is completely out of the question to change the semantics
>of .AND. itself.
Why? The only kind of code likely to suffer from the proposed change
is that invoking functions with side effects in the second operand of
.AND. Do you do this in your code? Do you care about those who do?
Oops ! I got mixed up between substitution and evaluation. But, indeed,
Dan Pop is right, let's change the semantics of the .AND. operator. I am
pretty sure that there are more programs out there that use evaluation
short-circuiting without their authors knowing that it is not standard
than programs that would be broken by the change.
Michel
--
| Michel OLAGNON email : Michel....@ifremer.fr|
| IFREMER: Institut Francais de Recherches pour l'Exploitation de la Mer|
>In <beland.8...@rimbaud.CERCA.UMontreal.CA> bel...@CERCA.UMontreal.CA (Michel Beland) writes:
>>she...@still3.chem.columbia.edu (Peter Shenkin) writes:
>>
>>>[[ comp.lang.c removed from Newsgroups: ]]
>>
>>>In article <beland.8...@rimbaud.cerca.umontreal.ca>,
>>>Michel Beland <bel...@CERCA.UMontreal.CA> wrote:
>>>...
>>>> IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
>>>>
>>>>which was rejected as illegal by all the compilers I tried...
>>>>.... Does anybody know why it is illegal ?
>>
>>>It's illegal because X3.9-1978 says, in Section 11.5, that the
>>>statement that follows a logical IF can be "anything except
>>>a DO, block IF, ELSE IF, ELSE, END IF, END or another logical IF
>>>statement."
>>
>>Sigh... I already know that. But why is this restriction in the
>>standard in the first place ? This seems to me to be an unnecessary
>>restriction.
>A cleaner solution than allowing that construct would be to change the
>.AND. operator semantics, so that it behaves like its C counterpart,
>&&, which guarantees left to right evaluation of its arguments and
>short circuiting (the evaluation stops when the result is known). This
>would allow writing:
> IF( M.GT.0 .AND. A(M).NE.0 )THEN...
>If M.GT.0 is false, the evaluation stops immediately because the result
>of the entire expression is false.
Although this would be a solution, I doubt that it will happen since it
would remove an opportunity for optimization.
Anyway, my question remain unanswered. I am changing the subject so
that more people can see it (probably a lot of people put the subject
of why is most HPC done in Fortran in their kill files). To repeat
myself:
Why is the construct
IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
explicitely forbidden by the standard ? What is the rationale ?
MODULE MY_EXTENSIONS
!
INTERFACE OPERATOR (.ANDALSO.)
MODULE PROCEDURE MY_AND
END INTERFACE
!
CONTAINS
LOGICAL FUNCTION MY_AND (A, B)
LOGICAL, INTENT (IN) :: A, B
IF (A) THEN
MY_AND = B
ELSE
MY_AND = .FALSE.
ENDIF
END LOGICAL FUNCTION MY_AND
END MODULE MY_EXTENSIONS
and
USE MY_EXTENSIONS
IF ( (M > 0) .ANDALSO. (A (M) > 0.0) ) THEN
Michel
: >|> Now, how could I best access b as if it were an n*n array?
: >|>
: >|> Should it be possible to declare a 'temporary' array, as in
: >|>
: >|> double **b;
: >|> b = malloc(sizeof(double)*n*n);
: >|> {
: >|> double b_array[n][n] = b;
: >|> }
: >Why? Why invent such an unreadable syntax. (Of course, what is unreadable to
: >one, is perfectly natural to another.)
: Because I want to access array elements with constant memory stride.
: This has been discussed on c.l.f and c.l.c just recently. The only way to
: get the intended effect right now is via
: b[n*i+j]
: (which is what f2c does). C definitely lacks a good matrix data type; there
: are about 10 ways to get it half right.
Perhaps the solution is to finally bite the bullet and NOT change or mix C's
existing pointer notation and semantics with the *completely new array type
that you will invent*.
Render unto C'sar that which is C'sar's ...... :-)
mbk
Answer 1: for 2d arrays in C it's best to do the index calculation
yourself (unfortunately).
double *b;
b = malloc(sizeof(*b) * n * n;
#define B(i, j) b[(i) * n + (j)]
/* use B(i, j) */
free(b);
Answer 2: use C++
vector<double> b(n);
b(i, j) = ...; // I use ( ) syntax for matrixes as it's easier to implement
// and fortran types can read it easier. You can also implement
// [][]
--
---
Tim Hollebeek 'There will be a better sig when I have time'
[ ... about : ]
> |> IF( M.GT.0 .AND. A(M).NE.0 )THEN...
[ ... versus : ]
> |> IF( M.GT.0 )THEN
> |> IF( A(M).NE.0 )THEN...
> |> Again, viewed pragmatically, this is just a pain in the ass, IMHO,
> |> compared to C. But I think you have more than this in mind, and
> |> I'd like to know what.
[ ... deletia ... ]
> Imagine you are on a machine which has a separate memory fetch and
> ALUnits, and M sits in the register, and a complicated calculation
> precedes this statement. Fortran allows you to start off the memory
> fetch of A(M) even before the ALU is free and can test M.GT.0. The idea
> is that if the user wants to force a wait, (s)he can always use the
> second form.
No.
The two forms:
[FORTRAN]
IF( M.GT.0 )THEN
IF( A(M).NE.0 )THEN...
[C]
if (m .gt. 0 && a[m] .ne. 0) { ....
are entirely different in efficiency, but that's not clear from this
limited example. The inefficiency, namely, is in the 'ELSE/else' clause:
The C form only has to carry one 'else' clause, while the Fortran one has
to have two - IDENTICAL - trailing ELSEs. The inefficiency here is in the
human endeavor to keep these two ELSE clauses IDENTICAL.
--
Toon Moene (to...@moene.indiv.nluug.nl)
Saturnushof 14, 3738 XG Maartensdijk, The Netherlands
Phone: +31 3461 4290; Fax: +31 3461 4286
URL: http://www.knmi.nl/hirlam
>Changing the standard to force short-circuiting disallows some
>optimizations that can be performed without short-circuiting.
>For instance given
> IF(I .LT. N .AND. A(I) .GT. 0.0)
>it can be much faster to first combine both conditions and jump based
>on that result rather than checking the left condition first (branches
>are expensive on many current architectures).
The trouble with this construct is that it can be used _only_ if you
know that I is within the bounds of A, whether it is smaller than N or
not. With the C semantics, A(I) will be evaluated only if I is smaller
than N and thus guaranteed to be within the bounds of A.
Changing the standard to force short-circuiting disallows some
optimizations that can be performed without short-circuiting.
For instance given
IF(I .LT. N .AND. A(I) .GT. 0.0)
it can be much faster to first combine both conditions and jump based
on that result rather than checking the left condition first (branches
are expensive on many current architectures). If you want short-circuiting
you should ask for it (as in ada with the "and" and "end else" operators).
Let's see.
I'll spare you my thoughts on Dijkstra's nationality and yours, and
simply suggest the following code:
IF ( M.GT.0 ) THEN
IF (A(M).NE.0) THEN
* Some stuff here
GOTO 100
ELSE
GOTO 101
END IF
END IF
100 CONTINUE
* The "else" case
101 CONTINUE
Or, if you prefer, the following which does not require labels:
LOGICAL T
T = M.GT.0
IF (T) T = A(M).NE.0
IF (T) THEN
* Your code
ELSE
* The one and only ELSE block
END IF
--
Sergio Gelato <gel...@sissa.it>
Strictly speaking, no programs can be "broken" in the sense of producing
invalid results, since the standard allows a compiler to shortcircuit the
second test. The question is, do you want to remove this opportunity for
optimization?
--
Sergio Gelato <gel...@sissa.it>
Strictly speaking, no programs can be "broken" in the sense of producing
invalid results, since the standard allows a compiler to shortcircuit the
second test. The question is, do you want to remove this opportunity for
optimization?
The answer is, NO. I thought this "let's define .AND. to be like C's
&&" thread was just a joke, but it appears not to be.
Folks, there is NO WAY to do Fortran's .AND. and .OR. in C (ANSI or K&R),
nor is there likely to be any way to do them in the future. This is
an advantage for Fortran, due to a lack of adequate expressive power
in C.
However, aside from the tedium of writing IF (A) THEN;IF (B) THEN and
such, C's && is easily done in Fortran. The ease of expression is
IMO a marginal advantage of C in this case, not nearly enough to counter
Fortran's.
Further, if you're going to define .AND. to be like &&, then you're
going to start defining sequence points in Fortran expressions. You're
going to have to change the language of future standards so that expressions
like "F(Y).AND.(Y.LE.0)" _are_ defined even if F() defines its single
argument (currently it is _not_ defined).
Why make Fortran as dumb as C in this regard? Sure, maybe some people
have been writing incorrect code in Fortran vis-a-vis .AND. and .OR.,
but that's an argument for checking code for correctness, or suggesting
they write in C in the first place, as that appears to be their wont.
>.... I thought this "let's define .AND. to be like C's
>&&" thread was just a joke, but it appears not to be.
I take responsibility for having started this subthread. I said
something like, "it's a bore <I actually used another expression :-)>
to have to say 'IF(I.GT.0)THEN;IF(Y(I).EQ.J)THEN...'". I never
imagined that anyone would actually suggest that the semantics
of the Fortran .AND. should be altered to reflect those of C's &&.
As has been pointed out by others, Fortran's assumption that order
doesn't matter allows for better optimization, whereas C's assumption
that order does matter allows for more condensed coding -- and, to my
mind, an easier transition from thought to code in those situations
where order does matter. But C then sacrifices efficiency in the
many situations in which order really doesn't matter. In fact,
in my own experience, order does matter perhaps 10% of the time.
You pays your money and takes your cherce....
>Why make Fortran as dumb as C in this regard? Sure, maybe some people
>have been writing incorrect code in Fortran vis-a-vis .AND. and .OR.,
>but that's an argument for checking code for correctness, or suggesting
>they write in C in the first place, as that appears to be their wont.
I will say that on SGI, at least, those writing Fortran that is
incorrect in this manner will soon discover the error of their ways.
I made a blunder not long ago by writing, in effect,
"IF(I.GT.0.AND.Y(I).EQ.J)THEN...". This promptly elicited a
segmentation fault when I was less than zero.
Hm, what do you do in this case:
do while( i .lt. n .and. a(i) .gt. eps )
blah blah
i = i + 1
end do
That is actually where I'd want C's && most. I find many cases where
the while loop is the logical way to express the algorithm (as opposed
to a do loop) but I always have to ensure it doesn't loop forever and
exceeds array bounds.
>
>Further, if you're going to define .AND. to be like &&, then you're
>going to start defining sequence points in Fortran expressions. You're
>going to have to change the language of future standards so that expressions
>like "F(Y).AND.(Y.LE.0)" _are_ defined even if F() defines its single
>argument (currently it is _not_ defined).
>
Yes, you are getting something like squence points but I don't see the
problem with your example. It is illegal now and I don't see why a
shortcicuitng .and. operator would change that.
Michael
--
Michael Lemke
Institute of Astronomy, Cambridge UK
(mic...@io.as.utexas.edu or UTSPAN::UTADNX::IO::MICHAEL [SPAN])
>Michael, it seems you are not paying attention. The point is not
>"what do you do in this case" -- you can simply rewrite the above
>into less-readable but CORRECT Fortran code -- but what do you do
>in C to get this Fortran equivalent:
>
> if (i(j).ne.0.and.l(qq).and.m(k,l).lt.5.3) ...
>
>The answer is, NOTHING.
???
What's wrong with:
if (i[j] != 0 && l[qq] && m[k][l] < 5.3) ...
or ^^^^
if (i(j) != 0 && l(qq) && m(k,l) < 5.3) ...
^^^^
This is optional.
I had to provide two alternatives because it's not clear whether i, l
and m are are functions or arrays (well, I ignored all the possible
combinations of functions and arrays, to save some bandwidth :-)
The Fortran syntax has some small problems :-)
> You are proposing to remove a Fortran feature
>that even ANSI C does not have, nor any proposed version of C I have
>encountered so far. (C++ doesn't have it either, I believe.) Despite
What is this misterious feature? How is it implemented by f2c?
If you need the current semantics of .AND. in C, you have it. Just use
the & operator and make sure that both operands evaluate to either 0 or 1
(all logical, relational and equality operators produce 0 or 1 as results).
It just happens that _nobody_ needs it in C and everybody prefers to use
&&.
In article <BURLEY.95J...@apple-gunkies.gnu.ai.mit.edu>,
Craig Burley <bur...@gnu.ai.mit.edu> wrote:
>In article <3s1rv4$o...@ictpsp10.ictp.trieste.it> gel...@oort.ap.sissa.it (Sergio Gelato) writes:
>
> Strictly speaking, no programs can be "broken" in the sense of producing
> invalid results, since the standard allows a compiler to shortcircuit the
> second test. The question is, do you want to remove this opportunity for
> optimization?
>
>The answer is, NO. I thought this "let's define .AND. to be like C's
>&&" thread was just a joke, but it appears not to be.
>
>Folks, there is NO WAY to do Fortran's .AND. and .OR. in C (ANSI or K&R),
>nor is there likely to be any way to do them in the future. This is
>an advantage for Fortran, due to a lack of adequate expressive power
>in C.
>
>However, aside from the tedium of writing IF (A) THEN;IF (B) THEN and
>such, C's && is easily done in Fortran. The ease of expression is
>IMO a marginal advantage of C in this case, not nearly enough to counter
>Fortran's.
Hm, what do you do in this case:
do while( i .lt. n .and. a(i) .gt. eps )
blah blah
i = i + 1
end do
How about
do
if (i.ge.n) exit
if (a(i).le.eps) exit
blah blah
i = i + 1
end do
??
That is actually where I'd want C's && most. I find many cases where
the while loop is the logical way to express the algorithm (as opposed
to a do loop) but I always have to ensure it doesn't loop forever and
exceeds array bounds.
Michael, it seems you are not paying attention. The point is not
"what do you do in this case" -- you can simply rewrite the above
into less-readable but CORRECT Fortran code -- but what do you do
in C to get this Fortran equivalent:
if (i(j).ne.0.and.l(qq).and.m(k,l).lt.5.3) ...
The answer is, NOTHING. You are proposing to remove a Fortran feature
that even ANSI C does not have, nor any proposed version of C I have
encountered so far. (C++ doesn't have it either, I believe.) Despite
the fact that the feature with which you're replacing the useful Fortran
feature is straightforwardly, if not always most elegantly, coded using
existing Fortran constructs.
Keep in mind that there are while/for/dowhile loops you can't even
write elegantly in ANSI C without resorting to the kind of stuff I had
to do to your Fortran example above. ANSI C provides a lot more
expressiveness in writing these loops, at a cost of many more expression
operators than Fortran has, and by omitting some critical ones Fortran
has (like .AND. and .OR.), while Fortran code can express pretty much
all the operators ANSI C has (let's ignore pointers and such for now).
But even ANSI C isn't perfect. (Try writing a C loop that elegantly
expresses that, say, its termination condition is calculated partly
by running its own loop. gcc's statement expressions allow this, but
not ANSI C.)
>Further, if you're going to define .AND. to be like &&, then you're
>going to start defining sequence points in Fortran expressions. You're
>going to have to change the language of future standards so that expressions
>like "F(Y).AND.(Y.LE.0)" _are_ defined even if F() defines its single
>argument (currently it is _not_ defined).
Yes, you are getting something like squence points but I don't see the
problem with your example. It is illegal now and I don't see why a
shortcicuitng .and. operator would change that.
It would change because the same people who think .AND. is C's && would
then be further encouraged (and rightfully so) to expect that the
left operand of && would be operated on first. So would I. I'd
consider any language that makes side effects in the lhs in (lhs&&rhs)
undefined to be seriously broken (assuming the expression is going to
be evaluated at all, I mean). Further, whether rhs side effects get
invoked should be defined based on the result of evaluating lhs.
It's a major change in how some Fortran compilers implement .AND. and
.OR. (not g77, which is forced to choose among the two C variants,
and picks && -- this will change someday, of course, when producing
optimal code becomes sufficiently important, which is why g77 doesn't
document this behavior).
So, if you're going to propose breaking .AND. and .OR. so that they
fit C's narrowly defined specifications, you also better be prepared
to propose how other aspects of the Fortran language will change ("improve"
in your views, of course -- "degrade" in mine).
: Hm, what do you do in this case:
: do while( i .lt. n .and. a(i) .gt. eps )
: blah blah
: i = i + 1
: end do
This is "obviously" f90 because of the do while and end do, so
I'd feel free to use other parts of the f90 do construct. I
find the exit and cycle statements convenient in many places;
this would be one. (And I almost never find that do while does
exactly what I want; there have been a few times it did, but they
are the exceptions). I'd probably write the above as
loop: do i = 1 , n
if (a(i) .lt. eps) exit loop
blah blah
end do loop
Other variations of style would also work.
--
Richard Maine
ma...@altair.dfrc.nasa.gov
The Fortran version does not guarantee that all of i(j),l(qq) and m(k,l) will
be called. The C version gives a guarantee about exactly what will be
evaluated, under what conditions and in which order. The way the Fortran
standard is written, if a compiler had access to two CPUs, it could evaluate
i(j) on one, l(qq) on another and then decide whether to call m(k,l).
No portable C expression can have this effect, C does not have a
don't-care-whether-you-evaluate-fully-as-long-as-the-answer-is-correct
logical operator. Use of && means i(j) and l(qq) cannot be run simultaneously
(in addition to the complication, that they could not have run simultaneously
anyway because of committee decisions): use of & means that m(k,l) _must_ be
called.
So, the fortran does express a compiler `pragma' that C does not portably
have.
Cheers
Tanmoy
> In article <9...@moene.indiv.nluug.nl>, I wrote:
> >[FORTRAN]
> > IF( M.GT.0 )THEN
> > IF( A(M).NE.0 )THEN...
> >[C]
> > if (m .gt. 0 && a[m] .ne. 0) { ....
Hmmm, this must be pseudo-C, of course I meant to write (of course :-):
if (m > 0 && a[m] != 0) { ...
> >are entirely different in efficiency, but that's not clear from this
> >limited example. The inefficiency, namely, is in the 'ELSE/else'
> >clause: The C form only has to carry one 'else' clause, while the
> >Fortran one has to have two - IDENTICAL - trailing ELSEs. The
> >inefficiency here is in the human endeavor to keep these two ELSE
> >clauses IDENTICAL.
> Let's see.
> I'll spare you my thoughts on Dijkstra's nationality and yours, and
> simply suggest the following code:
EEEEKSS, I'm not in the Computer Science department :-) :-)
> IF ( M.GT.0 ) THEN
> IF (A(M).NE.0) THEN
> * Some stuff here
> GOTO 100
> ELSE
> GOTO 101
> END IF
> END IF
> 100 CONTINUE
> * The "else" case
> 101 CONTINUE
[ ... And a comparable example using a logical instead of goto's ... ]
Am I alone in thinking that the C-type solution is much easier to
understand than these two ? The Fortran Standard is not the Holy Writ - it
can be changed (or augmented, which would be my preference here) if it is
deficient.
Nope. & requires both operands to be evaluated, .AND. does not. With
.AND. the compiler is allowed to find the optimal way to do it from
a number of alternatives:
evaluate left hand side and short-circuit
evaluate right hand side and short-circuit
evaluate both sides and do a logival operation
the first and third alternatives are present in C (but not as possible
alternatives for the compiler).
>In article <danpop.803573570@rscernix> Dan...@mail.cern.ch (Dan Pop) writes:
> > If you need the current semantics of .AND. in C, you have it. Just use
> > the & operator and make sure that both operands evaluate to either 0 or 1
> > (all logical, relational and equality operators produce 0 or 1 as results).
>
>Nope. & requires both operands to be evaluated, .AND. does not. With
This is true. The "fuzzy logic" of the Fortran .AND. can't be exactly
emulated in C.
>.AND. the compiler is allowed to find the optimal way to do it from
>a number of alternatives:
> evaluate left hand side and short-circuit
> evaluate right hand side and short-circuit
> evaluate both sides and do a logival operation
>the first and third alternatives are present in C (but not as possible
>alternatives for the compiler).
Which is a good thing, IMHO. In most cases, the programmer knows better
than the compiler what is the right order of evaluation in order to get
maximum performance from the short circuiting. This is a case where C
wins over Fortran, in terms of performance: there is no way to specify
to the Fortran compiler what is the best order of evaluation in terms of
performance and the compilers has no way to figure it out itself (because
it doesn't understand the algorithm). For example, if you know that
the probability of I < J to be true is ten times higher than the probability
of X < Y to be true, you can write in C:
if (X < Y && I < J) ...
and get the maximum performance from the short circuiting, but the
Fortran compiler has no clue which operand has to be evaluated first,
so getting it right is a matter of pure luck.
This advantage, combined with the possibility of writing
if (i < n && a[i] < eps) ...
make && the clear winner in terms of both performance and code
expressivity.
This is one case where "the programmer knows what he's doing" is better
than "the compiler knows what it's best for you". The advantages of
adopting the && semantics in Fortran outweigh by far the disadvantages.
>Dan Pop (Dan...@mail.cern.ch) wrote:
>: A cleaner solution than allowing that construct would be to change the
>: .AND. operator semantics, so that it behaves like its C counterpart, &&,
>: which guarantees left to right evaluation of its arguments and short
>: circuiting (the evaluation stops when the result is known). This would
>: allow writing:
>
>: IF( M.GT.0 .AND. A(M).NE.0 )THEN...
>
>: If M.GT.0 is false, the evaluation stops immediately because the result
>: of the entire expression is false.
>
>: Of course, you can't do this with the .AND. operator, the way it is
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>: defined right now.
> ^^^^^^^^^^^^^^^^^
>The F90 standard appears to contradict this statement. Section 7.1.7.1,
No, it doesn't.
>"Evaluation of Operands", states, "It is not necessary for the processor to
>evaluate all of the opperands of an expression, or to evaluate entirely each
>operand, if the value of the expression can be determined otherwise. This
>principle is most often applicable to logical expressions, . . ., but it
>applies to all expressions." Further rules on the evaluation of the .AND.
>operator are given in sections 7.1.7.6 and 7.2.4.
This is exactly the point. The Fortran compiler is allowed to evaluate
A(M).NE.0 _before_ M.GT.0 and this is precisely why
IF( M.GT.0 .AND. A(M).NE.0 )THEN...
is illegal in Fortran (assuming M can have values which are outside the
bounds of A). A more popular example is:
IF (Y /= 0 .AND. X / Y > Z) ...
which could be legal, assuming the && semantics, but it's currently
illegal.
The first version can be much faster.
Also, if I and J are in registers it can be nevertheless better to first
evaluate I < J; especially so if there are no registers free for X and Y.
>In article <danpop.803643364@rscernix> Dan...@mail.cern.ch (Dan Pop) writes:
> > if (X < Y && I < J) ...
> >
> > and get the maximum performance from the short circuiting, but the
> > Fortran compiler has no clue which operand has to be evaluated first,
> > so getting it right is a matter of pure luck.
> >
>If and only if short-circuiting is faster than not short-circuiting; which
>is not necessarily always the case. Consider with X, Y, I and J already
>in registers:
> sub r.x,r.y,r.tmp1
> sub r.i,r.j,r.tmp2
> land r.tmp1,r.tmp2,r.res
> bpos r.res,else_part
>vs.
> sub r.x,r.y,r.tmp1
> bpos r.tmp2,else_part
> sub r.i,r.j,r.tmp2
> bpos r.tmp2,else_part
>
>The first version can be much faster.
I'm affraid I don't get it. 2 sub's and a land can be much faster than
one sub? On what architecture?
>
>Also, if I and J are in registers it can be nevertheless better to first
>evaluate I < J; especially so if there are no registers free for X and Y.
Without short circuiting (your "faster" example above) you have to
evaluate both operands anyway (and "recycling" the registers of I and J,
might not be the optimal choice).
With short circuiting, starting with the expression which is almost
always true first isn't likely to buy you too much (on the contrary).
This is a case where C
wins over Fortran, in terms of performance: there is no way to specify
to the Fortran compiler what is the best order of evaluation in terms of
performance and the compilers has no way to figure it out itself (because
it doesn't understand the algorithm). For example, if you know that
the probability of I < J to be true is ten times higher than the probability
of X < Y to be true, you can write in C:
if (X < Y && I < J) ...
and get the maximum performance from the short circuiting, but the
Fortran compiler has no clue which operand has to be evaluated first,
so getting it right is a matter of pure luck.
Dan, I'm sorry, you still don't understand what the rest of us are
talking about.
You can write the C expression in Fortran as
IF (X.LT.Y) THEN
IF (I.LT.J) ...
We've already gone over this ground. YES, C's && and & are useful; YES,
it'd be nice if Fortran had them in a convenient and self-consistent
way (which is probably next to impossible); but NO, they aren't missing
in Fortran, they're just not easy to code. (Well, & can normally be
coded as .AND., but to really get &, one might need to use IAND() or,
in certain really bizarre cases, perhaps make a separate subroutine to
do the and-ing...but maybe that isn't ever necessary after all. I'm
not taking the time to think about this case right now. Note that
Fortran can definitely require one to code "functions" as subroutines
instead to express things easily expressed in C anyway, as discussed
here not too long ago.)
What is missing is that C does not have Fortran's .AND., nor any way
to express it, no matter HOW many lines of code you use.
It seems you think Fortran programmers neither know nor care about
frequency of cases, or expense of tests, or that when they do they're
probably using .AND. and .OR. incorrectly (thanks to Fortran's rendition
of those operators).
Maybe you're right, but it has been my experience that Fortran programmers
often do a great deal more analysis of frequency-of-execution and
expense-of-test type things than C programmers. I'm making wide
generalities here, but then again I've worked at a variety of iron
and compiler vendors, and hands down it was always clear the Fortran
people had more knowledge of how their _applications_ and _algorithms_
actually worked, in terms of expected expense. (Note that most of
_my_ programming, and that of my colleagues, has been at the systems/tools
levels, e.g. pidgin Fortran, PL1/G, C, and assembler. And especially
in PL/1 dialects, lack of && was a real pain in the butt. But, again,
it had everyday operators that are completely unexpressable in C.)
The point here is, maybe YOU think you ALWAYS know exactly which
operand of an "and" or "or" should be operated on first, but there
are plenty of Fortran programmers who know at least as much about
their problem domains as you know about yours and yet who willingly
admit (often by writing ".AND." or ".OR." in their programs) that
they DON'T know which operand should be evaluated first. (Thankfully,
they're writing in Fortran; in C they'd be forced to choose.)
Further, as Dik suggests in his post, but I'll try to make it clearer,
there is oftentimes NO WAY for even a C programmer to pick which test
is going to be easier/quicker for the compiler to try first. In a test
like "(I(J).AND.I(K))", where I is a LOGICAL array, it can be impossible
for a review of the _source_ code to reveal whether the compiler is going
to have an easier time evaluating I(J) or I(K) for the first test, if
performing one first is indeed wise (note that it isn't always best).
At least with Fortran, the compiler can decide which is easier. With
ANSI C, the _programmer_ is forced to choose which order is best, and
permanently express that choice in the code, as if the analysis had
already been done.
This particular problem may seem to have a workaround in C, but it doesn't
when the subscript expression involves invoking functions, especially
external ones. Remember, in Fortran, "(I(J()).AND.I(K()))", where I
is still a LOGICAL array, does _not_ require the implementation to invoke
functions J() _or_ K() at all if it can determine the value of the
expression without doing so (i.e. without incurring their side-effects,
if any). And if it needs to determine a particular value of one of
the operands of .AND., that freedom allows it to decide which is
easier to evaluate -- the one with J() as the subscript of I, or with
K(). And depending on the evaluations necessary for J() and K(), one
might be quite a bit easier to do at that point in the generated code
than the others (say, depending on what's sitting around in registers,
or what's likely to still be in the cache, etc.).
I'll say again, this is one of the HUGE advantages Fortran has over C,
though admittedly better compilers for both are needed to really show
them up -- in Fortran, the purpose of an expression is, basically, solely
to produce a value (if needed). In C, an expression is just a limited
form of a series of statements (though with gcc's statement expressions,
not really that limited, and of course C has subexpressions that also
act like Fortran's, but with incomplete operator sets, such as the lack
of Fortran's .AND. and .OR.).
One of the reasons I'm hesitant to recommend extending Fortran expressions
to include && and ||, and other such C operators, is that doing so
would effectively destroy this advantage. Sure, existing Fortran operators
would still operate as does C's limited set, but the trend and expectations
would be established that Fortran expressions also were little sequential
programs. It's a wonderfully powerful mode of expression (but if you want
that, use Scheme or LISP :-), but people accustomed to that level seem
to have great difficulty understanding the more-general (in OO terms,
less-refined) operators Fortran (and PL/1, &c) programmers know well.
You know, this thread has been an eye-opener for me. I've long thought,
based on some word-of-mouth research data or something I heard long ago,
that the two "really tough" concepts languages like C and Pascal
embodied that Fortran programmers had the most trouble understanding
(something like "50% of Fortran programmers [this was at least a
decade ago] are unlikely to ever understand these concepts") were:
- pointers
- recursion
Since much of my work makes use of these two concepts, I initially
found this shocking, but since realized that they are pretty challenging
(and, in the case of pointers, generally unnecessary in higher-level
language design -- recursive structures are presumably better, but
then you run headlong into the OTHER problem :-).
But I'd never heard of any cases of C programmers being unable to
wrap their heads around concepts fundamental to Fortran (and many
other languages) until now (and Dan Pop is not the only one to have
this trouble -- I got private email from someone showing how my
original Fortran example could be coded as a series of C _statements_
assigning the subexpressions to temporaries!! Needless to say, unless
I'm totally misunderstanding ANSI/K&R C, assigning the operands to
temporaries in statements makes the problem at least as bad).
Now, it's clear that perhaps a large percentage of C programmers
have a hard time understanding:
- and
- or
I say this partly tongue-in-cheek, because obviously they understand
the bit-level operations (probably better than lots of other programmers
using other languages), but they make an immediate and unnecessary
(certainly, at times, suboptimal) mental leap that, I believe, the
C language itself has required of them: the assumption that the "and"
and "or" operators necessarily must be coded in terms of "evaluate
the left operand, and only if necessary, the right" OR in terms of
"evaluate both operands, then do the bitwise operation".
But, as most people know when they're talking, sentences like
"You can spot Penny easily, she has purple eyes and a four-foot stack
of red hair."
and
"You can spot Penny easily, she has a four-foot stack of red hair
and purple eyes."
have essentially the same meaning vis-a-vis the "and", in the sense that,
in _both_ cases, the second person ("You") would be free to, based on
context (e.g. looking for Penny in a crowd of people, or contrariwise,
looking for Penny's face to appear in a small window near a door, where
the hair might not be visible), decide either to look _just_ for the
hair _or_ for the eyes, and not insist that the order in which the
"and" operands were expressed somehow governs the order in which they
should assess whether an individual is, in fact, Penny.
(Put another way: given the first sentence, I doubt even C programmers
would insist, when looking at a crowded room, at either:
- Ignoring a four-foot stack of red hair entirely until they first happen
to see someone with purple eyes
- Paying attention only to people they can spot and immediately tell
they have both purple eyes _and_ a four-foot stack of red hair
These are the C && and & operators, in order. Doubtless even C programmers
would understand that, whichever of the two sentences they were given
above, it was up to their understanding and judgement to decide whether
to pay attention first to hair, to eyes, to both at the same time (say,
in a group full of people with bizarre body colorings), or to do neither
and just yell "hey, Penny!!". The point being, that while they might
understand that the sentence _means_ that, they have no way to express
_that_ generic "and" operation in their native tongue -- C.)
[And I'm really snipping stuff here, so the attributions are wrong,
but it's just to quickly illustrate the context... -- burley]
if (m > 0 && a[m] != 0) { ...
> IF ( M.GT.0 ) THEN
> IF (A(M).NE.0) THEN
> * Some stuff here
> GOTO 100
> ELSE
> GOTO 101
> END IF
> END IF
> 100 CONTINUE
> * The "else" case
> 101 CONTINUE
Am I alone in thinking that the C-type solution is much easier to
understand than these two ? The Fortran Standard is not the Holy Writ - it
can be changed (or augmented, which would be my preference here) if it is
deficient.
You Are Not Alone.
The question is whether/how Fortran can be extended to include C's
expressiveness vis-a-vis && and || without ruining (whatever is left
of :-) Fortran's elegance. I'm thinking in particular of the truism
in Fortran that "an expression's purpose is to calculate a value
for that expression, if needed". With new operators like .AND_THEN.
and .OR_IF. (which we all agree must be intrinsics, i.e. understood by
the compiler, not via F90 extended operators in user code), this truism
becomes, well, a falseism.
I believe that, just as in C doing adjustable arrays properly should
embody at least all that can be done in Fortran (even F90/F95?) so
it doesn't end up with a technological cul-de-sac on its hands (i.e.
more crufty, weird things that don't interact properly with each
other -- see much earlier in this thread), we should do the same
in Fortran.
So, a possibly worthwhile extension to Fortran to support C's powerful
notion of sequence points would probably _not_ change the expression-level
syntax much at all, but would introduce _statement_-level notation to
express ways to calculate expressions (that might not be needed, thus
the statements need not be executed), in a syntax that makes things
sufficiently clear and concise for _Fortran_ (not C) programmers.
So, instead of .OR_IF. and .AND_THEN., which requires Fortran programmers
to basically learn a little (but not too much) C, I'd look for an
extension that allows any expression to be coded as a series of
statements including things like DO loops, SELECT CASE, and so on,
but clearly targeting the statements towards evaluating a single
expression.
To do the most general stuff, I imagine a syntax that would be quite
inelegant to do basic things like .OR_IF. and .AND_THEN., so I won't
bother posting my mental meanderings. My suspicion is that it cannot
be done. (Obviously in a technical sense any of these extensions can
be done, but I'm setting a much higher standard for them -- the
extensions must make sense and be at least somewhat feasible for
Fortran programmers to grasp, not C features tacked on to Fortran.)
On the other hand, maybe all you folks need is for F2000 to define
a macro processor that combines preprocessing-type stuff with MODULEs
and the like, so one can truly implement one's own .AND_THEN. and
.OR_IF. if desired. Then you can prefix all your code with the
single statement "USE C" and hack away to your heart's desire.... :-)
Seriously, though, these are, in my mind, tiny (but highly revealing)
_sub_-issues in a pretty wide universe of higher issues revolving around
language design, and I do a lot of thinking about that universe. That's
why I can't say one sub-universe is really that much better than the
other (e.g. Fortran vs. C), because there are times you really want to
express things one way vs. another (and here I'm talking about _ideal_
expression, not anything like "I just want to be able to type/read my
code faster and have it take up fewer bytes" -- which is valid as well,
but can be solved via better way than we're accustomed to, IMO).
I'm hoping to make time in the future to learn more about other languages
and, as appropriate, start design work on a new language that really is
a layering of program expression/translation phases, with an ultimate
underpinning (at the expression level) of a comparatively low level of
complexity. I've been designing this thing in my head for, oh, about
15 years, so it would be nice to start writing some of it down (or
typing it in, whatever), but perhaps some existing language out there
(and, yes, I'm keeping track of pointers people give me) already provides
most or all of what I want. (And, in case you think you already know
it, keep in mind that one requirement for it is the ability to
reasonably express the _precise_ semantics of an existing program in,
say, Fortran, C, or pretty much any other regular language, via direct
translation, without resorting to global analysis, etc...that is, a
facet of the language I want to use/build is the ability to express
what you really _mean_ to express, even if that means expressing the
original Fortran or C in a simply translated form. I don't get
particularly excited about great new languages that require existing
code to be rewritten, much less redesigned, to take advantage of them.)
On the CDC Cyber 750 the first would take (this is all from memory, but
roughly correct) 9 cycles if branch not taken, 15 cycles if branch taken.
The second, 12 cycles if first branch taken, 18 cycles if second branch
taken and 12 cycles if no branch taken. (sub (assuming integer sub),
3 cycles; two can be pipelined. land 2 cycles. branch 3 cycles if not
taken, 9 cycles if taken.) There are more machines were a branch is
expensive; whether it is taken or not.
[ snip ]
>Why is the construct
>
> IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
>
>explicitely forbidden by the standard ? What is the rationale ?
>
>--
>Michel Beland bel...@CERCA.UMontreal.CA
>professionnel de recherche tel: (514)369-5223 fax: (514)369-3880
>CERCA (CEntre de Recherche en Calcul Applique)
>5160, boul. Decarie, bureau 400, Montreal (Quebec), Canada, H3X 2H9
Since (as you point out in the snipped-out text) no one who Knows(TM)
has replied, I'll venture my speculation:
The syntax of
IF ( M.GT.0 ) IF( A(M).NE.0 ) THEN
statement1
statement2
statement3
ENDIF (1)
is a little confusing. Normally, a logical IF applies
*only* to the statement immediately following. This
would give something like:
IFA: IF ( M.GT.0 ) THEN
IFB: IF( A(M).NE.0 ) THEN
ENDIF IFA
statement1
statement2
statement3
ENDIF IFB (2)
which is illegal, but might mean:
IF ( M.GT.0 ) THEN
IF( A(M).EQ.0 ) GO TO 100
ENDIF
statement1
statement2
statement3
100 CONTINUE (3)
But you probably meant:
IF ( M.GT.0 ) THEN
IF( A(M).NE.0 ) THEN
statement1
statement2
statement3
ENDIF
ENDIF (4)
Of course, one could simply say that construction (1)
is equivalent to construction (4), but that complicates
the syntax of the language, so that a compiler can't
just blindly translate
IF ( logical-expression ) statement
into
IF ( logical-expression ) THEN
statement
END IF
to reduce the number of control constructions it has
to understand.
It probably seemed simpler to all concerned to require programmers
to write construction (4) if that's what they meant.[*]
In fact, it wouldn't surprise me if a number of X3J3 (the US
committee responsible for the Fortran standard) members wish
they could eliminate the logical IF altogether (like they want
to do with the arithmetic IF).
The same logic applies to all the statements forbidden to
be controlled by a logical IF.
[*] For what it's worth: it would be kind of nice to have a "structured"
way to write construction (3).
--
Alan McKenney E-mail: mcke...@cims.nyu.edu (INTERNET)
Courant Institute,NYU,USA ...!cmcl2!cims.nyu.edu!mckenney (UUCP)
: IF( M.GT.0 .AND. A(M).NE.0 )THEN...
: If M.GT.0 is false, the evaluation stops immediately because the result
: of the entire expression is false.
: Of course, you can't do this with the .AND. operator, the way it is
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: defined right now.
^^^^^^^^^^^^^^^^^
: --
: Dan Pop
: CERN, CN Division
: Email: Dan...@mail.cern.ch
: Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland
The F90 standard appears to contradict this statement. Section 7.1.7.1,
"Evaluation of Operands", states, "It is not necessary for the processor to
evaluate all of the opperands of an expression, or to evaluate entirely each
operand, if the value of the expression can be determined otherwise. This
principle is most often applicable to logical expressions, . . ., but it
applies to all expressions." Further rules on the evaluation of the .AND.
operator are given in sections 7.1.7.6 and 7.2.4.
By following these rules, a standard-conforming processor is ALLOWED to
short-circuit the evaluation of the complete expression; it is not REQUIRED
to do so. Similarly, a standard-conforming processor is ALLOWED to evaluate
expressions in strict left-to-right order; it is not REQUIRED to do so.
Why is this the case? To allow a standard-conforming processor to implement
certain optimizations which would be prohibited if strict left-to-right
evaluation was required.
Sincerely,
--
Craig T. Dedo Internet: Craig...@mixcom.com
Elmbrook Computer Services Voice Phone: (414) 783-5869
17130 W. Burleigh Place
Brookfield, WI 53005 Disclaimer: These opinions are mine alone.
USA They do NOT represent any organization.
"Those who would give up essential Liberty, to purchase a little temporary
Safety, deserve neither Liberty nor Safety." -- Benjamin Franklin
Not clear to me. What is your speculation about why
IF(M.GT.0) IF (A(M).NE.0) A(M) = M/A(M)
is forbidden, but
IF(M.GT.0) IF(A(M)) 10,20,30
is not? (The `block' argument does not work!)
It seems to me that logical if is treated for all purposes as a single
statement block if, whereas an arithmetic if is treated as a more elemental
construct. The reason for this must be somewhere buried in history...
(possibly because a compiler already has to support computed and assigned
goto as target of a logical if, it was felt that an arithmetic if is
`similar'; but a logical if was `different'? That simply shifts the answer
one stage back: does not answer it.)
Speak for yourself. In many cases *I* have no idea whether the piece of
code I am writing today for use in a certain regime will someday be reused
in a different regime where my assumptions on the probability distribution
of values for some subexpressions are reversed.
Also, unless I am writing code for a particular architecture I would be
hard pressed to guess which of two nearly equivalent orders of evaluation
will result in faster code. And I certainly don't want to learn too much
about the number of cycles needed for each operation (including memory fetches,
which will depend on what happens to be in the cache).
Currently, Fortran is superior to C in this area because it offers you a
choice. Use .AND. and let the compiler figure out what it thinks is best;
or use the
LOGICAL T
T = subexpression_1
IF (T) T = subexpression_2
IF (T) T = subexpression_3
approach. (Replace IF(T) with IF(.NOT.T) if you need a || somewhere.)
Of course you can use | and & in C, along with temporary variables,
but that has slightly different semantics (bitwise operations on
integers) which may not be the optimal way of doing things on some
architectures. Fortran still wins by allowing the compiler a wider
choice of machine level instructions to use.
There is another reason not to change the semantics of .AND. (though
I repeat, I have nothing against the addition of an .AND_THEN. to the
language, as long as it is a different operator). Fortran is meant to
provide straightforward translation of mathematical formulae. A mathematician
generally doesn't care, when writing a formal logical expression, which
is the best way of evaluating it. That may well depend on information that
is not available to her. For example, is M(K,L) a table lookup or a function
call? The formula often does not depend on that, and the corresponding
Formula Translation is reusable in different contexts (just change the
declaration of M, the algebra stays formally the same).
Normally, one would begin by writing out the formula. Only when it is
important for optimization would one help the compiler by forcing
a particular order of evaluation.
>wins over Fortran, in terms of performance: there is no way to specify
>to the Fortran compiler what is the best order of evaluation in terms of
>performance and the compilers has no way to figure it out itself (because
>it doesn't understand the algorithm). For example, if you know that
The user may not know much better. The proper way to do it is to use
a nice software tool that instruments the code, *measures* the probabilities
in a sample of actual production runs, then rewrites the source accordingly.
Such tools do exist. A language like Fortran that lets the programmer
express the notion "there are no a priori reasons for imposing a particular
order of evaluation; please use whatever is best given the current optimization
settings" gives these tools more leeway, and is therefore preferable.
>This is one case where "the programmer knows what he's doing" is better
>than "the compiler knows what it's best for you". The advantages of
>adopting the && semantics in Fortran outweigh by far the disadvantages.
The advantages of retaining the current .AND. semantics (and optionally
adding an .AND_THEN. with the semantics of C's && if you really find
logical temporaries too ugly) outweigh by far the (nonexistent) advantages
of redefining the meaning of .AND.
Please don't tell me that redefining .AND. would improve the efficiency of
those Fortran codes that already happen to have ordered logical subexpressions
in the optimal order of evaluation. For every such code one can find another
code where the subexpressions follow a different order (that of the formula
in some research article, or whatever) that has nothing to do with the optimal
order of evaluation. Backward compatibility argues in favour of leaving .AND.
as it is.
I would also dispute the assumption that shortcircuiting is always faster
than evaluating both operands of an .AND. This need not be true on a
vector machine (classic Cray, etc.) If shortcircuiting is not required
(i.e. if there are no side effects, including runtime exceptions) then it
is more reasonable to let the compiler make the decision.
--
Sergio Gelato <gel...@sissa.it>
[snippage]
> But you probably meant:
>
>
> IF ( M.GT.0 ) THEN
> IF( A(M).NE.0 ) THEN
> statement1
> statement2
> statement3
> ENDIF
> ENDIF (4)
>
>
> Of course, one could simply say that construction (1)
> is equivalent to construction (4), but that complicates
> the syntax of the language, so that a compiler can't
> just blindly translate
>
> IF ( logical-expression ) statement
>
> into
>
> IF ( logical-expression ) THEN
> statement
> END IF
>
> to reduce the number of control constructions it has
> to understand.
>
>
>
> It probably seemed simpler to all concerned to require programmers
> to write construction (4) if that's what they meant.[*]
[more snippage]
> Alan McKenney E-mail: mcke...@cims.nyu.edu (INTERNET)
> Courant Institute,NYU,USA ...!cmcl2!cims.nyu.edu!mckenney (UUCP)
>
>>>>
If you want a simpler construct, what's wrong with
IF ( (M.GT.0) .AND. (A(M).NE.0) ) THEN
statement
.
.
END IF
, which is functionally equivalent to IF (condition1) THEN
IF (condition2) THEN
.
.
END IF
END IF,
since *both* expressions must evaluate to .TRUE. if the statments are to
be executed.
Many FORTRAN compilers provide for partial conditional evaluation, so chances
are the conjunction will not add execution overhead. Check your compiler
manual.
>In article <beland.8...@rimbaud.CERCA.UMontreal.CA> bel...@CERCA.UMontreal.CA (Michel Beland) writes:
> [ snip ]
>>Why is the construct
>>
>> IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
>>
>>explicitely forbidden by the standard ? What is the rationale ?
> Since (as you point out in the snipped-out text) no one who
> Knows(TM) has replied, I'll venture my speculation:
> The syntax of
> IF ( M.GT.0 ) IF( A(M).NE.0 ) THEN
> statement1
> statement2
> statement3
> ENDIF (1)
> is a little confusing. Normally, a logical IF applies
> *only* to the statement immediately following. This
> would give something like:
[ Examples of possible interpretations of above code deleted ]
> But you probably meant:
> IF ( M.GT.0 ) THEN
> IF( A(M).NE.0 ) THEN
> statement1
> statement2
> statement3
> ENDIF
> ENDIF (4)
This is indeed what I meant. The other interpretations you gave were
stretching my idea pretty far. In my proposed construct, IF (M.GT.0)
is a logical IF and IF (A(M).NE.0) THEN is the beginning of a block
IF. It seems to me that the only obstacle to make it legal would be
your objection that the block IF spans several lines, which is
inconvenient for the compiler (but I do not think it is a good reason
to forbid it).
However, the code
IF (M.GT.0) IF(A(M).NE.0) A(M)=1
is also forbidden and your objection is not relevant here, since the
second logical IF is on one line. Why is the above line forbidden by
the standard ?
> It probably seemed simpler to all concerned to require programmers
> to write construction (4) if that's what they meant.[*]
> In fact, it wouldn't surprise me if a number of X3J3 (the US
> committee responsible for the Fortran standard) members wish
> they could eliminate the logical IF altogether (like they want
> to do with the arithmetic IF).
Hmm... The logical IF is easy to understand and very widely used.
Removing it from the standard would not be a good idea in my humble
opinion...
: You Are Not Alone.
Well, maybe BOTH of you *are* alone thinking that FORTRAN codes must include
GOTO statements!!!
Regards,
Andre
In article <3s6ov9$8...@gauss.cims.nyu.edu>, mcke...@gauss.cims.nyu.edu (Alan
M. McKenney) writes:
<snip>
|> >Why is the construct
|> >
|> > IF( M.GT.0 ) IF( A(M).NE.0 )THEN...
|> >
|> >explicitely forbidden by the standard ? What is the rationale ?
<snip>
|> has replied, I'll venture my speculation:
<snip>
|> The same logic applies to all the statements forbidden to
|> be controlled by a logical IF.
Not clear to me. What is your speculation about why
IF(M.GT.0) IF (A(M).NE.0) A(M) = M/A(M)
is forbidden, but
IF(M.GT.0) IF(A(M)) 10,20,30
is not? (The `block' argument does not work!)
I think it does. The logical IF makes a little "block" around its statement.
The arithmetic IF is a single statement with no "blockness" about it. It's
pretty gross, but nobody who already knows arithmetic IF (I'll stay quiet on
this one :-) is likely to think the above means
IF(M.GT.0) THEN
IF (A(M).LT.0) GOTO 10
ENDIF
IF (A(M).EQ.0) GOTO 20
IF (A(M).EQ.0) GOTO 30
while beginning a _block_ where a single statement is already implicitly
"blocked" (by logical IF) is likely to confuse people.
PLEASE, would everyone who is trying to "fix" a language like Fortran
remember, about 1% of the job is coming up with a specific meaning
for a specific construct. Around 99% of it is designing constructs whose
meanings are fairly clear to even marginally experienced readers.
For this reason, it is irrelevant whether you can clearly identify a
_meaning_ for "IF (expr) IF (expr) IF (expr) THEN...". Because many
people will have trouble understanding it, it is irrelevant that you
can construct a compiler that will have no such trouble. (It surprised
even me that people more knowledgable than I have claimed even
Fortran's DO WHILE(expr) should be avoided...but the explanation,
which makes at least a little sense, is that some people will read this
construct as "do these statements, exit AT ANY POINT that (expr)
becomes false", whereas the equivalent DO/ENDDO cannot be similarly
misinterpreted. If these knowledgable people have indeed run into
programmers making such incorrect assessments, imagine what they'd
run into with constructs like those being proposed in this newsgroup!!)
Programming languages are emphatically NOT about simply getting the
computer to do what you want it to do. They are about communicating
effectively with other human beings. If they were only about communicating
with computers, we'd all be writing in assembler, etc. If human beings
can't readily understand what you're writing, it's pretty unimportant
whether a computer can. Tools that address just that need are available
in plenty -- many of them are old, dead languages with an increasingly
short supply of rabid fans, but You Know Where You Can Find Them.
As far as permitting logical-IF within logical-IF, that has much more
hope of both working and being understood, but I think it is unwise because
it will be hard for people to keep track of the several implicit little
"blocklets" made by the statements:
IF (expr) IF (expr) IF (expr) statement
has three blocklets. I'd prefer, if the above expressibility was really
desired, to see
IF (expr) ANDIF (expr) ANDIF (expr) statement
or
IF (expr) ORIF (expr) ORIF (expr) statement
as an example of doing && and || in Fortran. But I'd expect the proposal
to include providing this sort of power in other constructs with similar
expressibility (so we don't have to memorize lots more keywords :-) in
places like IF/THEN and especially ELSEIF.
In other words, once you have the above (my ANDIF/ORIF proposal, which
I'm not really proposing), then it really becomes hard to understand
why you _couldn't_ say "THEN" instead of supplying a statement, i.e. by
starting a block IF in the same way...and similarly for ELSEIF.
Then, while you get back to the issue of "blocklets", you can at least
try to handwave the blocklet issue by teaching/treating the statement
chain as a sort of meta-expression, a la C's expressions with sequence
points (&&, ||).
But, if you do the above, I suggest you really do it right (i.e. the above
being quite half-baked) and provide more C operators (and, yes, I really
do want this stuff, but question whether it can all be put into Fortran
elegantly -- your gut will tell you whether the examples below are
improving on or destroying Fortran as its own language), as in:
IF (expr) ANDIF <(expr) ORIF (expr)> THEN
(I.e. using angle brackets here as kind of meta-parens in that they
bracket a series of conditional expressions to be tested in sequence
as necessary.)
Or:
IF (expr) ANDIF ((expr) ORIF (expr)) THEN
(I.e. making up a whole new syntactic mechanism, the infix operator
that requires its operands to be in parens and that doesn't have
surrounding periods, such that the operator is more like a macro-
level operator that decides whether to evaluate its operands based
on whatever it wants.)
The latter of the above two is more easily envisioned as being a general
extension of Fortran expressions, but perhaps the angle-bracket version
can be done that way as well (or some other thing).
Once you get here, then more operators than ANDIF/ORIF seem useful.
But, some of them are preferably done as prefix operators, making
the extra-paren approach above less palatable, because it introduces
ambiguities when there's only one operand (and is harder to read anyway
in that it doesn't visually indicate a special form of expression,
one involving sequence points a la C -- so maybe angle brackets
are indeed better).
Anyway, going back to the angle brackets, one might want to generalize
expressions such that any expression beginning with "<" is a more
general form that involves potential sequence points, offers
miniature statements, and such, ending with a corresponding ">".
(Let's ignore the fact that "(<a>b>)" becomes hard to parse for now;
pretend square brackets could be used instead...I'm just trying to
avoid introducing yet another set of characters to the discussion. ;-)
In that case, why allow
IF (expr) ANDIF (expr) statement
when you can provide
IF (<(expr) ANDIF (expr)>) statement
? That is, if you're heading in the direction of C, why stop at mucking
with a couple of statements that solve your particular short-term problem?
Why not properly extend the language to really move towards C's
expressiveness, without introducing a bunch of short-term specific
solutions that'll become outdated when you (or others) introduce
the greater expressiveness someday anyway?
You could, after all, have:
IF (expr) THEN
...
ELSEIF (<FOO: DO I=1,100;
& IF (M(I).LT.0.1) EXIT FOO;
& END DO FOO;
& IF (I.LE.100)>)
...
END IF
Here, without making sure I'm using a syntax that really works in all
cases (some more sugar might be needed), I've shown how mini-statements
supporting all the necessary power can be introduced to this extended
Fortran expression.
Note that I haven't had to extend the Fortran statements at all this
way.
Do you really want to extend Fortran _statements_ further, given the
above illustration of how the power you want can be provided along
with vastly more power and expressiveness in a more consistent
way _without_ introducing yet more limited, weird statement forms?
And if you find the above suggestions really ugly, are you really
sure you are able to provide exactly the new _statement_ forms that
everyone will want and use with no confusion but without whetting
their appetite with "yet more C stuff that Fortran can't do [easily]"?
For my money (and effort, if I do the design and/or coding for trying
this stuff out in g77, for example), I'd much prefer the greater power
and expressiveness afforded by enhancing expressions along the lines
I propose than by introducing more narrowly-defined (and possibly
obscure and someday obsolete) statement forms.
Not that you don't get into lots of weird issues using my approach.
Should label definitions be allowed (not just constructs), so people
can "GOTO" within these mini-blocks? Should the definitions be
local to the mini-block, or in the same scope as the containing
procedure? Same thing with declarations, wouldn't it be nice
to declare and use variables (_definitely_ these should be local
to the mini-block)? Of course, since expressions nest, so would
these mini-blocks, so how about providing outer-scope visibility,
and how would that affect macro processing (e.g. an inner mini-block
refers to "FOO" which it does not declare, but an enclosing mini-block
_and_ its outermost program unit both declare "FOO" as different things...
to which does the inner FOO refer)? How about writing nested
functions (a la statement functions) within those mini-blocks, so
they can be used there?
The nice thing about the above issues, though, is that they are
fairly easy to resolve by forgetting about the overall Fortran
context and just doing what is well-known and works in other languages
like C, Scheme, and so on.
Note, though, that if you go down _this_ path, at this point in time,
not only had you better take into account what F95/F2K do or need
to do, you also must really consider whether this is the time and
opportunity to introduce powerful OO concepts available in other,
more modern languages. What will message passing look like in
your Fortran, for example?
And, what you'll find within the mini-block expressions is that the
urge to design mini-statement syntax "properly" will conflict with
the urge to make those mini-statements look as much like their
regular kin in Fortran. Will you make assigments look exactly the
same, even if this means making the overall syntax uglier to resolve
ambiguities that might arise in the grammar? Will you keep the commas
to separate "begin,end,incr" in an iterative DO, or use clearer
verbage (a la PL/1 -- this bit me coming from Fortran, because in
PL/1 a DO loop like "do i=1,10,1" means "execute this loop three
times, first with i=1, second with i=10, third with i=1" -- but
it's due to PL/1's _greater_ expressiveness, with regard to looping
constructs, than Fortran's).
And, if you make mini-statements better in any way than their regular
kin, will you correspondingly extend the regular kin? If not, will
there be a way for people to write mini-statements (mini-blocks) across
multiple non-continued lines so they can code entire program units
that way? Meanwhile, won't the regular kin become deprecated over
time if they aren't improved along with the mini-statement kin?
Language Design Is Fun. Think Ahead. Never Give A Gun To Ducks.
:-)
It seems to me that logical if is treated for all purposes as a single
statement block if, whereas an arithmetic if is treated as a more elemental
construct. The reason for this must be somewhere buried in history...
(possibly because a compiler already has to support computed and assigned
goto as target of a logical if, it was felt that an arithmetic if is
`similar'; but a logical if was `different'? That simply shifts the answer
one stage back: does not answer it.)
I think the answer is just that arithmetic IF preceded logical IF. Also,
that arithmetic IF is easier to implement with late-50s software technology
-- there's no implicit block around the stuff after the expression.
That is, the compiler need only parse three numbers (labels) separated
by commas, it doesn't have to parse any possible statement that might appear
there. (Even the code in g77 to do logical IF is not free of hair,
and has had a few bugs reported and fixed in it over the years.)
In this sense, arithmetic IF is really nothing other than a glorified
GOTO, which is part of the reason it is deprecated by so many people.
(The three-way-ness of the test being the other part. I happen to really
like that kind of thing, but I'm pretty twisted as you can tell. :-)
|> ELSEIF (<FOO: DO I=1,100;
|> & IF (M(I).LT.0.1) EXIT FOO;
|> & END DO FOO;
|> & IF (I.LE.100)>)
If you are going to propose anything on these lines, then I think it ought to
be neater than this :-) <...> could be like inline nested procedures ...
(I am not a language designer: I use fortran: and am happy with it. Fortran
90 already starts giving me a headache :-)
<snip>
|> It seems to me that logical if is treated for all purposes as a single
|> statement block if, whereas an arithmetic if is treated as a more
elemental
|> construct. The reason for this must be somewhere buried in history...
|> (possibly because a compiler already has to support computed and
assigned
|> goto as target of a logical if, it was felt that an arithmetic if is
|> `similar'; but a logical if was `different'? That simply shifts the
answer
|> one stage back: does not answer it.)
|>
|> I think the answer is just that arithmetic IF preceded logical IF. Also,
|> that arithmetic IF is easier to implement with late-50s software technology
|> -- there's no implicit block around the stuff after the expression.
I am not sure about this: isn't there an anachronism in thinking of logical
IF as a miniature block if? My memory in these matters is terrible: but isn't
block if a 77 feature, logical if a IV feature, and arithmetic one a II
feature?
What was the argument then (when people weren't even thinking of `block
if's)? It is obvious by the prohibition that even then logical if was being
treated as `two' statements: a statement for testing, and a statement to
skip over if the test failed. putting a logical if as the second statement
would make the first one skip over these `two' instead of one: hence the
prohibition. Arithmetic if is impossible, or at the least very
difficult, to formulate in this skip over language: without already
having the concept of `else' which accompanied block ifs. Isn't such a
bizarre interpretation worthy of curiosity?
Of course, if block ifs and logical ifs came simultaneously, I do not have a
question except to myself: why rememember things as being bizarre when they
are not :-)
Cheers
Tanmoy
P.S. You asked why I know about arithmetic ifs? I first learnt programming
long back from an old guy who thought IBM 1620 with fortran II was a
great improvement over unit record machines ... I did not doubt him.
>I think it does. The logical IF makes a little "block" around its
>statement. The arithmetic IF is a single statement with no "blockness"
>about it. It's pretty gross, but nobody who already knows arithmetic
>IF (I'll stay quiet on this one :-) is likely to think the above means
[ Long and interesting post deleted. ]
I think I will stop asking silly questions like why nested logical IFs
are not permitted, so that you can have more time to work on g77. :-)
I never thought there were so much to say about that matter...
I have only, up to now, encountered this sort of condition in contexts
where optimization is marginal, outside of the inner loops.
My personal feeling is that, most of the time, although there might be an
optimization opportunity, it is not worth while to go for it:
-Optimization because of simpler expressions computed first and
short-circuiting -> Impose short-circuiting and ask the programmer
to be smart enough to put simple expressions first.
-Optimization because of faster evaluation of related expressions ->
Are-you sure that it is better to evaluate faster all subexpressions
than to evaluate, slower indeed, only a few of them and short-circuit ?
If large impact on some applications can be shown, then let's go for
.ANDTHEN. and .ORELSE., but I would prefer to avoid adding more and
more new operators to the language.
Michel
--
| Michel OLAGNON email : Michel....@ifremer.fr|
| IFREMER: Institut Francais de Recherches pour l'Exploitation de la Mer|
The situation gets more confusing if you add the possibility of an
ELSE or ELSEIF; does
IF ( M.GT.0 ) IF ( A(M).NE.0 ) THEN
statement1
ELSE
statement2
ENDIF (A)
mean
IF ( M.GT.0 ) THEN
IF ( A(M).NE.0 ) THEN
statement1
ELSE
statement2
ENDIF
ENDIF (B)
or
IF ( M.GT.0 ) THEN
IF ( A(M).NE.0 ) THEN
statement1
ENDIF
ELSE
statement2
ENDIF (C)
In the post that first asked this question in another thread
(<beland.8...@rimbaud.CERCA.UMontreal.CA>), Michel Beland
wrote:
> [ snip ]
>(since the ELSE part would not apply to the condition on M, but only on
>the condition on A(M)), ...
> [ snip ]
i.e., he assumes interpretation (B). I agree, if this construct were
indeed defined, this would probably be its interpretation. Nevertheless,
I'm sure lots of people would be bitten at least once (and perhaps
repeatedly) by falsely assuming interpretation (C), especially with a
small change to the indentation:
IF ( M.GT.0 ) IF ( A(M).NE.0 ) THEN
statement1
ELSE
statement2
ENDIF (A')
Every novice programmer will sooner or later try something like:
IF ( M.GT.0 ) IF ( A(M).NE.0 ) THEN
statement1
ELSE
statement2
ELSE
statement3
ENDIF (D)
(possibly with an extra ENDIF thrown in between statement2 and the
second ELSE).
As Craig Burley rightly points out,
>...it is irrelevant whether you can clearly identify a
>_meaning_ for "IF (expr) IF (expr) IF (expr) THEN...". Because many
>people will have trouble understanding it, it is irrelevant that you
>can construct a compiler that will have no such trouble. ...
--
Leonard J. Moss <l...@slac.stanford.edu> | My views don't necessarily
Stanford Linear Accelerator Center | reflect those of SLAC,
MS 97; P.O. Box 4349; Stanford, CA 94309 | Stanford or the DOE
In article <BURLEY.95J...@apple-gunkies.gnu.ai.mit.edu>,
bur...@gnu.ai.mit.edu (Craig Burley) writes:
<snip>
|> ELSEIF (<FOO: DO I=1,100;
|> & IF (M(I).LT.0.1) EXIT FOO;
|> & END DO FOO;
|> & IF (I.LE.100)>)
If you are going to propose anything on these lines, then I think it ought to
be neater than this :-) <...> could be like inline nested procedures ...
I am NOT going to propose this, just show what would be, I think,
rather inevitable if people succeed at pushing Fortran down the
slippery precipice of offering the notational convenience of C....
(I am not a language designer: I use fortran: and am happy with it. Fortran
90 already starts giving me a headache :-)
Me too! :-)
|> I think the answer is just that arithmetic IF preceded logical IF. Also,
|> that arithmetic IF is easier to implement with late-50s software technology
|> -- there's no implicit block around the stuff after the expression.
I am not sure about this: isn't there an anachronism in thinking of logical
IF as a miniature block if? My memory in these matters is terrible: but isn't
block if a 77 feature, logical if a IV feature, and arithmetic one a II
feature?
Yes. I'd say you're right that thinking of logical IF as a miniature
block IF is somewhat of an anachronism, but I think it is not a surprising
one for modern Fortran programmers.
What was the argument then (when people weren't even thinking of `block
if's)? It is obvious by the prohibition that even then logical if was being
treated as `two' statements: a statement for testing, and a statement to
skip over if the test failed. putting a logical if as the second statement
would make the first one skip over these `two' instead of one: hence the
prohibition. Arithmetic if is impossible, or at the least very
difficult, to formulate in this skip over language: without already
having the concept of `else' which accompanied block ifs. Isn't such a
bizarre interpretation worthy of curiosity?
Not sure I understand all of what the above says, but I think I agree
with it. Looking at logical IF in its contemporary perspective, indeed
does seem to offer a more persuasive reason not to allow nested logical
IFs. (I.e. the "skip next statement if condition is false" view, vs.
my suggested "enclose next statement in implicit block" view.)
Of course, if block ifs and logical ifs came simultaneously, I do not have a
question except to myself: why rememember things as being bizarre when they
are not :-)
You're right that logical IFs preceded block IFs.
It's this historical progression that explains why Fortran 95 allows
IF (A) 10,20,30
10 IF (I.EQ.0) GOTO 40
IF (M.LT.N) THEN
CALL FOO
END IF
but does not allow
IF (M.LT.N) THEN
CALL FOO
END IF
IF (I.EQ.0) GOTO 40
IF (A) 10,20,30
because the latter has the variants of IF in the wrong order. ;-)
If large impact on some applications can be shown, then let's go for
.ANDTHEN. and .ORELSE., but I would prefer to avoid adding more and
more new operators to the language.
I've been nibbling around the edges of this in my other long posts
(amazing they could nibble around the edges of anything, eh? :-)...but...
...if you want to propose adding C's && and || to Fortran, I STRONGLY
recommend you do NOT use the ".NAME." syntax (i.e. the syntax
used for .AND., .OR., .NOT., .TRUE., .FALSE.). Already this syntax
is a bit stretched to denote binary and unary operators _and_ operands
(constants)...it might be very difficult for programmers to understand
that .ANDTHEN./.ORELSE. (or whatever you'd name them) are in yet another
category -- operators that do NOT evaluate their operands before
applying the operation, but that conditionally evaluate them in a
specific order.
Again, this gets back to good language design. I suppose you could
look at .NAME. as a syntax meaning "anything we couldn't throw in using
a more natural manner", but many Fortran programmers probably don't
think of it that way. Reeducating them to do so probably would prove
quite challenging. (The point being that, for most intents and purposes,
aside from the special cases of .TRUE. and .FALSE., Fortran programmers
today rightly believe that any expression like FOO.OP.BAR can be
replaced by SOMEOP(FOO,BAR) if SOMEOP is a function that does the same
thing as .OP.. .ANDTHEN. and .ORELSE. would introduce yet more exceptions
to this, ones that are not as visible at the parsing level as they
are for .TRUE. and .FALSE. (which are visible because they're operands,
not operators).)
><snip>
>I am not sure about this: isn't there an anachronism in thinking of logical
>IF as a miniature block if? My memory in these matters is terrible: but isn't
>block if a 77 feature, logical if a IV feature, and arithmetic one a II
>feature?
><snip>
Yes, logical IF was a feature of both Fortran IV and the correspsonging
standard generally called Fortran 66 (ANSI X3.9-1966, to purists ;-).
I'd guess that the prohibition against nesting logical IFs came more from
questions of implementation (remember this was 30 years ago) than
usability. There's no natural reason to cut off the recursion at two,
after all, and I wouldn't be surprised if the compiler writers of the day
found the prospect of 19 continuation lines worth of nested logical IFs a
little daunting (though perhaps someone more knowledgeable than I about
the compiler technology of the time will tell me that this would have been
trivial, even in 1966). The standardizers could have picked an arbitrary
limit, of course -- in fact that's what they did, the limit they picked
just happened to be one ;-).
Seriously, they may have felt that establishing the basic functionality of
logical IF was sufficient, that the extension to nested logical IFs was
"obvious" and that, given the lack of a natural choice for a nesting
limit, they would leave all decisions about how deeply, or whether, to
permit nested logical IFs to the marketplace.
I believe there were some vendors who did, indeed, provide this extension,
at least until Fortran 77 and the block IF came along.
In article <BURLEY.95J...@apple-gunkies.gnu.ai.mit.edu> bur...@gnu.ai.mit.edu (Craig Burley) writes:
> look at .NAME. as a syntax meaning "anything we couldn't throw in using
> a more natural manner", but many Fortran programmers probably don't
You've been thinking f77 too long.
.user_operator.
is precisely how users get to add operators for their new datatypes.
I know!! But they're adding operators a la .AND., .OR., and so on.
As I pointed out in my post, anything they write via (left.OP.right)
they can write via SOMEOP(left,right).
And as other people already pointed out in this thread (or one of its
bushy members :-), .AND_THEN. can NOT be implemented via F90/F95,
in that it would not be equivalent to ANDTHEN(left,right), where
ANDTHEN is a function, because generally evaluation of operands happens
before evaluation or operator.
Perhaps the fact that there are an increasing number of _intrinsic_
procedures that have non-evaluating behavior (e.g. KIND()) will
mitigate this somewhat by doing the dirty work of teaching
the unwashed masses that function invocations don't necessarily always
mean evaluation of arguments before function...and _maybe_ this
kind of reeducation can be accomplished for the .OP. syntax as well.
But given the (apparent) fact that even "DO WHILE()" confuses some
people, because its syntactic sugarness can mislead (vs. the simple
"DO;IF (.NOT. ...)" alternative), I suspect that there would be
lots of confusion for quite a while if .OP.-style operators were
created that didn't necessarily evaluate their operands. A new syntax
that is clearly different would be much more helpful (though note that
"IF () THEN;IF () THEN" already accomplishes that to some degree).
(This is all aside from the issue I raised and explained in earlier
posts, that once you have .AND_THEN. or any mechanism to accomplish
that in expressions, you then have sequence points in expressions.
And once you let _that_ cat out of the bag, you might as well commit
all sorts of other "sins". Don't add convenient features just for
the sake of convenience is the lesson here -- you might just get what
you want, in spades. Anyone wanting .AND_THEN. and .OR_ELSE. had
better be ready for .THEN_EVAL. (C's comma operator), .ASSIGN_FROM.
(C's assignment operator =), .PREINCREMENT. (--x), .POSTINCREMENT. (++x),
.INCREMENT_BY. (x+=y), .DECREMENT_BY. (x-=y), and so on.)
My first thoughts went along the IF ( (M > 0 .AND.) A(M) /= 0) THEN direction.
Perhaps, to avoid ambiguities, IF ( (? M > 0 .AND. ?) A(M) /= 0) THEN, which
would use a short-circuiting ``expression with operator'' evaluator (? ?).
It could even also be used for multiplications: don't bother to compute the
second operand if the first one is zero. But I was then told that some
languages offer the ANDTHEN and ORELSE operators (ADA ?), and naively
went into the ecumenical path when I should probably have stayed on the
Good Old Obvious Fortran ((;-)**2) one.
So, what about
IF ( (? M > 0 .AND. ?) A(M) /= 0) THEN
?
>James Craig Burley, Software Craftsperson bur...@gnu.ai.mit.edu
Michel
Haven't you been thinking f00 too early ?
First, underscores are not allowed in user defined operators (and won't
be, I guess, until some time because of parsing headaches like
0._my_kind.X.Y.0._my_op._my_other_kind.0._my_kind..0
)
Second, Craig is right, a Fortran programmer who defines a new operator
cannot make it short-circuiting, and is thus not going to expect pre-defined
ones to be either (or even worse, might then expect that he can indeed
make his own short-circuiting operators with, for instance,
as_in_my_first_post>> LOGICAL FUNCTION MY_AND (T1, T2)
as_in_my_first_post>> LOGICAL, INTENT (IN) :: T1, T2
as_in_my_first_post>> IF (T1) THEN
as_in_my_first_post>> MY_AND = T2
as_in_my_first_post>> ELSE
as_in_my_first_post>> MY_AND = T1
as_in_my_first_post>> ENDIF
as_in_my_first_post>> END FUNCTION MY_AND
)
IF ( (? M > 0 .AND. ?) A(M) /= 0) THEN
Seems a bit hard to scan to me, I mean visually speaking. (And I
don't think ? was added to the character set for F90, but I'm
probably wrong -- is ? international enough? Let's not get into
trigraph/digraph necessities, like C did.... 8-)
Further, what troubles me is that it introduces a whole new syntax
to provide only one small portion of a larger set of expressive
operators that C already has. E.g. how will the (? ?) syntax you
propose be used to provide C's sequence operators comma (,), equals (=),
and so on? They won't. So for them, you'll need yet another new
syntactical addition...or, you'll just punt and do them using
vanilla Fortran syntax, which you could probably then use in place
of the (? ?) stuff you're already introduced and now have to support
forever....
Again, and again, and again, I say: don't bother trying to design
Fortran's version of && and || until you know what you're doing with
language design. If your design doesn't elegantly and cleanly handle
C's =, ,, +=, ++, and other operators, it isn't worth doing at all, IMO.
Because once you step over the line into C's notational convenience,
there will be NO WAY to convince people that they don't really want
the other C operators, i.e. that && and || were all they really wanted.
--
...
> look at .NAME. as a syntax meaning "anything we couldn't throw in using
> a more natural manner", but many Fortran programmers probably don't
...
You've been thinking f77 too long.