[comp.lang.fortran] intrinsic functions, math operators

jlg@lanl.gov (Jim Giles) (09/20/88)

From article <1531@ficc.uu.net>, by peter@ficc.uu.net (Peter da Silva):
> This is not true. Just because something in 'C' has the form of a function
> does not mean it is forced to be a function:
> 
> 	getchar()
> 	min()/max() on many machines
> 	feof()
> 	isprint()
> 

This is one of the reasons that C is less portable than Fortran.  The set
of intrinsic functions is not defined anywhere.  I may indeed want to write
my own versions of some of the above functions (add pow() to the list).  If
one implementation allows me to do so, another shouldn't prevent me - unless
the standard says that the function is intrinsic - in which case, the 
implementor is allowed to switch.  The present C 'standard' (such as it is) 
is K&R.  K&R doesn't mention any intrinsics as far as I know.  As I said 
before, the ANSI C standard will probably address this issue.

>> A secondary objection is that
>> exponentiation is a mathematical operation for which mathematicians
>> and others have always had (and still expect) a shorthand syntax.
> 
> This syntax is, however, not the one Fortran uses. The mathematical syntax
> for exponentiation is actually not displayable in ASCII text.

That is _not_ a valid argument for omitting exponentiation as an operator.
Subscripting is not expressible in ASCII text either.  Yet both Fortran
_AND_ C have a syntax for subscripting.  I would argue (as I have before)
that the syntax for mathemetical operations in a programming language
should be as close as possible to the syntax used by the target user
community for those same operations.  Constraints of the character set
and of the compiler may prevent you from getting _exact_ identity with the
user's preferred syntax - but you should still try to get close.

J. Giles
Los Alamos

chris@mimsy.UUCP (Chris Torek) (09/20/88)

>In article <1531@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>>... Just because something in 'C' has the form of a function
>>does not mean it is forced to be a function:
>> 
>> 	getchar()
>> 	min()/max() on many machines
>> 	feof()
>> 	isprint()

[i.e., these are often macros]

In article <3748@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>This is one of the reasons that C is less portable than Fortran.  The set
>of intrinsic functions is not defined anywhere.

`Old C' has no intrinsics (in the Fortran definition) to define, hence
the second statement is true.  The first contains two implications, one
of which is true and one of which is, at best, a matter of opinion.  C
is less portable than it might be: if `getc' is a function, the statement

	c = getc(files[index++]);

works.  On other machines, getc() is a macro that evaluates its argument
more than once, producing bizarre results.  Someone with an implementation
of the first sort can write code with embedded side effects and get away
with it; that code is not `de facto portable'.

>The present C 'standard' (such as it is) is K&R.

K&R 1st ed. is too weak a standard: the existing `de facto' standard is
much richer, but also more vague.  The semantics of `common extensions'
to K&R 1 (including such things as the math library) are not particularly
well defined, so it is hard to use these `portably'.  (All these words
are in quotes only because I am not willing to define them here now.)

>As I said before, the ANSI C standard will probably address this issue.

It does indeed.

>>[Mathematical exponentiation] syntax is, however, not the one Fortran
>>uses. The mathematical syntax for exponentiation is actually not
>>displayable in ASCII text.

>That is _not_ a valid argument for omitting exponentiation as an operator.

True.

>... the syntax for mathemetical operations in a programming language
>should be as close as possible to the syntax used by the target user
>community for those same operations.

I would suggest `^', which not only looks like `go up', but also exists
in both ASCII and EBCDIC, and even appears as an up-arrow in old
ASCII.  (Before some ANSI standard whose exact number I never knew, the
characters [ \ ] and ^ were often displayed as four arrows.  Some of
you may even have four arrows showing on your screens now.  Bonus
quadrivia points to those who remember which way the arrows went :-) .)

Anyway, I happen to believe that intrinsic functions make perfectly
good `operators'.  (Just another matter of opinion.)  (I could ask
why Fortran does not have a syntax for min and max operators....)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

peter@ficc.uu.net (Peter da Silva) (09/20/88)

In article <3748@lanl.gov>, jlg@lanl.gov (Jim Giles) writes:
> From article <1531@ficc.uu.net>, by peter@ficc.uu.net (Peter da Silva):
> > This is not true. Just because something in 'C' has the form of a function
> > does not mean it is forced to be a function:

> > 	getchar()
> > 	min()/max() on many machines
> > 	feof()
> > 	isprint()
> > 

> This is one of the reasons that C is less portable than Fortran.  The set
> of intrinsic functions is not defined anywhere.

And it shouldn't be.

> I may indeed want to write
> my own versions of some of the above functions (add pow() to the list).

So #undef them.

> > This syntax is, however, not the one Fortran uses. The mathematical syntax
> > for exponentiation is actually not displayable in ASCII text.

> That is _not_ a valid argument for omitting exponentiation as an operator.

No, and I'm not saying it is. What I'm saying is that just because something
is an operator in mathematics doesn't mean it has to be one in any given
programming language. What about integration, differentiation, and so on?
There's even a syntax for differentiation that is expressable in ASCII.
-- 
Peter da Silva  `-_-'  Ferranti International Controls Corporation.
"Have you hugged  U  your wolf today?"            peter@ficc.uu.net

jlg@lanl.gov (Jim Giles) (09/21/88)

From article <13635@mimsy.UUCP>, by chris@mimsy.UUCP (Chris Torek):
>>... the syntax for mathemetical operations in a programming language
>>should be as close as possible to the syntax used by the target user
>>community for those same operations.
> 
> I would suggest `^', which not only looks like `go up', but also exists

Unfortunately, it did _not_ exist on the old 026 keypunches - and _THAT'S_
the origin of the Fortran character set constraints.  I agree, `^' is
a much better choice.  It just wasn't here when it was needed.  `**' was
chosen as a rather obvious lesser_of_many_evils - it at least suggests
_something_ to do with multiplication (which is how most people regard
exponentiation).

> why Fortran does not have a syntax for min and max operators....)

Suggest a standard mathematical notation for min and max which most
potential users are familiar with - I wouldn't oppose including it.

J. Giles
Los Alamos

jlg@lanl.gov (Jim Giles) (09/21/88)

From article <1554@ficc.uu.net>, by peter@ficc.uu.net (Peter da Silva):
>> I may indeed want to write
>> my own versions of some of the above functions (add pow() to the list).
> 
> So #undef them.

#undef _only_ works on macros.  If pow() is not implemented as a macro,
#undef will do _nothing_ to it.  

By the way, if you really believe that intrinsic functions should not be
identified as such, you'd better hurry - the ANSI committee is about to 
define a whole raft of them.  It is a good idea though, it helps make 
code portable (something that C is particularly bad at).

> There's even a syntax for differentiation that is expressable in ASCII.

And, when differentiation is added to a programming language, the syntax
you mention is the one that should be used.

J. Giles
Los Alamos

d25001@mic.UUCP (Carrington Dixon) (09/21/88)

In article <13635@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>
>I would suggest `^', which not only looks like `go up', but also exists
>in both ASCII and EBCDIC, and even appears as an up-arrow in old
>ASCII.

     I don't think so.  There is certainly no "^" character on any
3270-type keyboard that I have ever used, and I cannot find a "^"
character on any copy of the familiar IBM "System/370 Reference Summary"
that I have.  "Shift-6" (the usual location of "^") is the EBCDIC
NOT sign (sort of a hyphen with a tail).


Carrington Dixon
UUCP: { convex, killer }!mic!d25001

fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts) (09/21/88)

In article <3907@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>
>By the way, if you really believe that intrinsic functions should not be
>identified as such, you'd better hurry - the ANSI committee is about to 
>define a whole raft of them.  It is a good idea though, it helps make 
>code portable (something that C is particularly bad at).
>

1) an intrinsic function is one the compiler knows something about so
   that it can perform kicky optimizations like in line expansion.  A
   function does not have to be intrinsic to aid portability.  It need
   only be required by the standard committe.  A library
   implementation is perfectly acceptable.  If I understand correctly
   which ANSI committee you are refering to (C?) The proposal is *not*
   for intrinsic functions, but for required library functions.
   Implementation left to the implementer.


2) If a function is part of a library, rather than generated by the
   compiler, it become a matter of loader sophistication to override
   the standard version with my own version.  All I need is away to
   specify the order in which the loader locates globals, and an
   override on "multiply defined" 'errors.'

3) C is not 'particularly bad at portable code.'  I have written
   100s of K lines of code in C, Pascal, and Fortran.  Each has
   problems with portability.  For the kind of code I've written,
   ([parts of ] operating systems, compilers, data base packages,
   graphics, and  some largish numerical codes) and the kind of
   porting I've had to do, C has been much easier to deal with
   than either of the others. Your milage will vary, but there
   isn't really anything inherent in any of the languages that
   make it hard to write portable code. Or not. (During the mid 70's,
   I made    quite a bit of lose change as a consultant moving Fortran
   between IBM, DEC, Xerox and CDC machines.  I can tell you
   incredible horror stories about Fortran portability problems
   which *still* haven't been fixed.  Particularly in i/o, but
   also in other areas.)


+-+-+-+     I don't know who I am, why should you?     +-+-+-+
   |        fouts@lemming.nas.nasa.gov                    |
   |        ...!ames!orville!fouts                        |
   |        Never attribute to malice what can be         |
+-+-+-+     explained by incompetence.                 +-+-+-+

ok@quintus.uucp (Richard A. O'Keefe) (09/21/88)

In article <3823@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>Suggest a standard mathematical notation for min and max which most
>potential users are familiar with - I wouldn't oppose including it.

Depends on how you define "most potential users".
The notation I know and like is min= /\, max= \/, which is what's
normally used for lattices.  (If you use the usual ordering .FALSE. < .TRUE.
they even work nicely as logical operators, P/\Q = P.AND.Q .)

peter@ficc.uu.net (Peter da Silva) (09/21/88)

In article <3907@lanl.gov>, jlg@lanl.gov (Jim Giles) writes:
> From article <1554@ficc.uu.net>, by peter@ficc.uu.net (Peter da Silva):
> >> I may indeed want to write
> >> my own versions of some of the above functions (add pow() to the list).

> > So #undef them.

> #undef _only_ works on macros.  If pow() is not implemented as a macro,
> #undef will do _nothing_ to it.  

If pow() is not defined as a macro, it's not intrinsic. See below.

> By the way, if you really believe that intrinsic functions should not be
> identified as such, you'd better hurry - the ANSI committee is about to 
> define a whole raft of them.  It is a good idea though, it helps make 
> code portable (something that C is particularly bad at).

They're defining functions that can be made instrinsic by including a header
file that #defines them to something like __INTRINSIC_func__. If you don't
want the intrinsic version, you #undef them. It doesn't require either that
they be made intrinsic nor that people assume they are.

> > There's even a syntax for differentiation that is expressable in ASCII.

> And, when differentiation is added to a programming language, the syntax
> you mention is the one that should be used.

Anyone know what syntax Macsyma uses to indicate differentiation.

By the way all this talk of operators and mathematics... what about
division?
-- 
Peter da Silva  `-_-'  Ferranti International Controls Corporation.
"Have you hugged  U  your wolf today?"            peter@ficc.uu.net

jlg@lanl.gov (Jim Giles) (09/22/88)

From article <1028@amelia.nas.nasa.gov>, by fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts):
>    which ANSI committee you are refering to (C?) The proposal is *not*
>    for intrinsic functions, but for required library functions.
>    Implementation left to the implementer.

Look again.  There are a number of functions which the committee says
the processor is allowed to optimize or expand in-line.  The rationale
document recommends that the in-line expansion be passed to the processor
as a macro in one of the default includes - but (as far as I know) this
is not the _required_ way of in-line expansion.

Furthermore, if implementation were left to the implementor, _many_
functions would be implemented by the compiler - they're easier to do
that way (if you really want them to be optimized).  If I were writing
a C compiler, I would certainly do pow() in-line.  What you claim is that
the ANSI C committee is listing a group of required functions and that
these are _required_ to be implemented in a library form.  I don't think
this is true.

J. Giles
Los Alamos

jlg@lanl.gov (Jim Giles) (09/22/88)

From article <457@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe):
> they even work nicely as logical operators, P/\Q = P.AND.Q .)

Yes I am presently designing a language in which \/ is OR and /\ is
AND.  It's too bad about lattice theorists using these symbols for 
max and min, but the majority of my target users are into latices
(some of them are though - so like I said, it's too bad).

J. Giles
Los Alamos

fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts) (09/22/88)

In article <3957@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>From article <1028@amelia.nas.nasa.gov>, by fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts):
>>    which ANSI committee you are refering to (C?) The proposal is *not*
>>    for intrinsic functions, but for required library functions.
>>    Implementation left to the implementer.
>
>Look again.  There are a number of functions which the committee says
>the processor is allowed to optimize or expand in-line.  The rationale
>document recommends that the in-line expansion be passed to the processor
>as a macro in one of the default includes - but (as far as I know) this
>is not the _required_ way of in-line expansion.
>

Err, the draft standard actually allows in-line expansion of any known
function, including user defined functions, provided certain rules
(which I don't remember) are followed.  It also requires that this be
overridable.  GNU C and G++ (Gnu C++), for example, already have this
ability as a user option.  It is an attempt to give the (definitely
justifable) advantages of intrinsics while maintaining the ability to
override.

>Furthermore, if implementation were left to the implementor, _many_
>functions would be implemented by the compiler - they're easier to do
>that way (if you really want them to be optimized).

Well, maybe.  When I'm implementing a compiler, I try to stay as far
away from knowing semantics of called routines as possible, because
the techniques I use are easier to implement if they discover the
semantics on the fly than if they carry them around as imbedded
knowledge.  (Easier, but more expensive, when the semantics never
change, which is rarely.)

>  If I were writing
>a C compiler, I would certainly do pow() in-line.  What you claim is that
>the ANSI C committee is listing a group of required functions and that
>these are _required_ to be implemented in a library form.  I don't think
>this is true.
>

No.  I did not claim that the functions are _required_ to be
implemented as libraries.  You are deliberately confusing the converse
and inverse of a statement.  I claimed that the functions are required
to be present, and that the mechanism of implementation was undefined.
They may be implemented by inline generation by a knowledgable
compiler, by macros in standard headers (provided side effects are
correctly handled), or by libraries.  My reading of the draft shows
any of these to be allowed; provided that in all cases the user is
allowed to override the standard version with a private version.

Inline code generation is an allowable substitution in any event,
provided the compiler can correctly determine that the substitution
produces a semantically equivalent executable.  Hopefully it is only
ever done as a space/time tradeoff optimization.

(Creon Levit says:  "Oh yeah, the old space/time tradeoff.  Takes more
 space and more time.)

+-+-+-+     I don't know who I am, why should you?     +-+-+-+
   |        fouts@lemming.nas.nasa.gov                    |
   |        ...!ames!orville!fouts                        |
   |        Never attribute to malice what can be         |
+-+-+-+     explained by incompetence.                 +-+-+-+

jlg@lanl.gov (Jim Giles) (09/22/88)

From article <1031@amelia.nas.nasa.gov>, by fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts):
> [...]                                  My reading of the draft shows
> any of these to be allowed; provided that in all cases the user is
> allowed to override the standard version with a private version.


Yes, but the method of overriding the standard version is different for
each of the implementation methods that you mention.  This means that
a code which really does override a standard procedure definition will
not be portable.  It is this lack of portability that I object to.

By the way, you said you liked your optimizer to figure out a new semantics
for itself rather than coding it into the compiler.  This works just fine
if the information required for the optimizer to do it's work can be
gleaned from the code skeletons or macros that define the new feature.
If not (as in the case of complex numbers, for example) the method
of modifying the compiler will usually produce better code that one which
is extended by the other mechanisms.  For example, if I have a bunch of
macros that define SINE and COSINE functions (how to evaluate), I still
won't be able to optimize SIN(x)*SIN(x)+COS(x)*COS(x) as well as a compiler
could do if it had the semantics of trig functions built-in (the optimal
evaluation strategy is to replace the whole expression with the constant 1).

J. Giles
Los Alamos 

dodson@mozart.uucp (Dave Dodson) (09/22/88)

In article <3957@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>If I were writing a C compiler, I would certainly do pow() in-line.

Considering the complexity and length of a properly written pow()
routine, it does not appear to me to be practical for the compiler to
in-line it.  It is not adequate to evaluate pow(x,y) as exp(y*log(x))
unless additional precision is used.  See "Software Manual for the
Elementary Functions" by Cody and Waite, for a description of an
appropriate algorithm.

----------------------------------------------------------------------

Dave Dodson    {uiucdcs,sun,uunet,harvard,killer,usenix}!convex!dodson
Convex Computer Corporation      Richardson, Texas      (214) 952-0234

fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts) (09/22/88)

In article <3976@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>From article <1031@amelia.nas.nasa.gov>, by fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts):
>> [...]                                  My reading of the draft shows
>> any of these to be allowed; provided that in all cases the user is
>> allowed to override the standard version with a private version.
>
>
>Yes, but the method of overriding the standard version is different for
>each of the implementation methods that you mention.  This means that
>a code which really does override a standard procedure definition will
>not be portable.  It is this lack of portability that I object to.
>

Hmm.  Good point.  I agree.

>[comment on my comment about not wanting the compiler to know
  semantics in advance . . .], I still
>won't be able to optimize SIN(x)*SIN(x)+COS(x)*COS(x) as well as a compiler
>could do if it had the semantics of trig functions built-in (the optimal
>evaluation strategy is to replace the whole expression with the constant 1).
>

This is true, but only accurate when the expression evaluates to a
constant.  You couldn't (because of finite precision) replace
1-COS(X)*COS(X) with SIN(x)*SIN(x) and guarentee the same results.
Although, if you can determine at compile time that COS is
deterministic in X then you can replace 1-COS(X)*COS(X) with
(t=COS(X),1=t*t) The case that evaluates to another function is much
more common than the case that evaluates to a constant.

For now, I'm willing to give up the occasional constant-replacement
win for the optimizations I can get by concentrating on manipulating
on the fly knowledge, and leave the level of algabric sophistication
that you are contemplating to Macsyma, Mathematic, et al.

Eventually, I want the optimizer for my language to be two optimizers.
The first one should be Knuth's "program rewritter" which rewrites my
program in my source language making substitutions such as the above.
This one should mostly be an algebraic rewriting system and should be
concerned only with the kind of transformations that your example
represent.  The second one would do only the optimizations that
can't/shouldn't be done at the source level such as strength reduction
and cse on adress arithmentic.  It would be part of the compiler.

[Knuth wanted the program rewritter to be interactive - asking if it
 was OK to apply various transformations.  Pacific Sierra Research has
 done a product along these lines for vectorizing Fortran called
Forge.]


Marty

+-+-+-+     I don't know who I am, why should you?     +-+-+-+
   |        fouts@lemming.nas.nasa.gov                    |
   |        ...!ames!orville!fouts                        |
   |        Never attribute to malice what can be         |
+-+-+-+     explained by incompetence.                 +-+-+-+

jlg@lanl.gov (Jim Giles) (09/23/88)

From article <1033@amelia.nas.nasa.gov>, by fouts@lemming.nas.nasa.gov.nas.nasa.gov (Marty Fouts):
> This is true, but only accurate when the expression evaluates to a
> constant.  You couldn't (because of finite precision) replace
> 1-COS(X)*COS(X) with SIN(x)*SIN(x) and guarentee the same results.

True, but Fortran would allow this anyway since optimized expressions
need only to be mathematically identical, not computationally identical
(see section 6.6 of the standard).
 
> that you are contemplating to Macsyma, Mathematic, et al.
                                                  ^

That's Mathematica.  And I agree.  I have long wanted to write the
mathematics preprocessor that Knuth talks about.  In fact, I want a
more powerful system which could take (for example) a set of differential
equations and a 3-d initial geometrical set-up and automatically
generate a Fortran code which efficiently runs a finite differencing
technique on the problem.

J. Giles
Los Alamos 

ok@quintus.uucp (Richard A. O'Keefe) (09/23/88)

In article <3960@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
:From article <457@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe):
:> they even work nicely as logical operators, P/\Q = P.AND.Q .)

:Yes I am presently designing a language in which \/ is OR and /\ is
:AND.  It's too bad about lattice theorists using these symbols for 
:max and min, but the majority of my target users are into latices
:(some of them are though - so like I said, it's too bad).

I don't understand why it's "too bad".  My point was that the use of
/\ for minimum and \/ for maximum is CONSISTENT with their use for
.AND. and .OR.; the conventional lattice representation of the logical
values is .FALSE. = 0, .TRUE. = 1, .AND. = /\, .OR. = \/.

jlg@lanl.gov (Jim Giles) (09/24/88)

From article <596@convex.UUCP>, by dodson@mozart.uucp (Dave Dodson):
> [...]
> Considering the complexity and length of a properly written pow()
> routine, it does not appear to me to be practical for the compiler to
> in-line it.  [...]

pow(x,3) == x*x*x appears to me to be both accurate and short enough
to be expanded in-line.  The same goes for pow(x,-4.) == 1/((x*x)*(x*x).
_Most_ uses of the exponentiation operator in Fortran are of this kind.
Therefore, _most_ uses would benefit from in-line optimization.  Things
like pow(x,3.14159) could still call an external to solve - that's the
power of letting the compiler in on the semantics of the basic operations.


J. Giles
Los Alamos 

peter@ficc.uu.net (Peter da Silva) (09/24/88)

In article <596@convex.UUCP>, dodson@mozart.uucp (Dave Dodson) writes:
> In article <3957@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
> >If I were writing a C compiler, I would certainly do pow() in-line.

> Considering the complexity and length of a properly written pow()
> routine, it does not appear to me to be practical for the compiler to
> in-line it.

No, but there are certain cases of pow that can be handled in line, with
the rest passed off to the library routine:

	pow(floatvar, integer);
	pow(floatvar, constant), for certain constants.
	pow(constant, floatvar), for certain constants.

I'm sure Jim can come up with lots more...
-- 
Peter da Silva  `-_-'  Ferranti International Controls Corporation.
"Have you hugged  U  your wolf today?"            peter@ficc.uu.net