Path: utzoo!utgpu!water!watmath!clyde!rutgers!sri-spam!ames!amdcad!sun!quintus!ok From: ok@quintus.UUCP (Richard A. O'Keefe) Newsgroups: comp.lang.c Subject: Re: Power operator? Summary: storm in teacup Message-ID: <521@cresswell.quintus.UUCP> Date: 11 Jan 88 07:11:34 GMT References: <11169@brl-adm.ARPA> <1559@rtech.UUCP> <622@PT.CS.CMU.EDU> Organization: Quintus Computer Systems, Mountain View, CA Lines: 117 In article <622@PT.CS.CMU.EDU>, edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes: 1> Actually any operation in a languge need not generate functions calls - 1> have we heard of inline expansion? ... 2> implement. I don't think anyone will question the reasonableness 2> of an infixed notion for exponentiation. ... 3> properties become harder to detect when using a functional format 3> (integers must be typed coerced into doubles). On machines with 3> no hardware support for exponetiation, the answer maybe one could His points (1) and (3) contradict each other. In fact his point (3) is the direct opposite of C's defaults: at present, whenever you do X Y "the usual conversions" are done, which means amongst other things that if one operand is double, the other *will* be converted (which Wyatt says *won't* happen), whereas if you call a function integers will only be promoted to 'int'. In C, functional *syntax* gives us the freedom to have operands of different types: extern double pow(double base, double expt); -vs- extern double rtp(double base, int power); Note that these are quite different functions: rtp(-3.0, 2) is well defined, but pow(-3.0, 2.0) is illegal and should signal a matherr. (In Common Lisp, (EXPT -3.0 2.0) --> #C(9.0 0.0), a complex number.) Just to play devil's advocate, I'll question the reasonableness of an infix operator for exponentiation. Point 1: Many correspondents seem not to realise that there are TWO distinct operations (which happen to coincide for strictly positive bases). It would be unwise to provide special syntax for something so little understood. Point 2: At present, all the arithmetic operators apply "the usual conversions". Now the operation most commonly wanted is base ** k for k a constant integer expression, and base some size of float. The fact that k isn't (and mustn't) be converted makes "*%" unlike other operators. But there is nothing surprising about the function rtp(). Suppose we add an operator for pow(). This *would* apply "the usual conversions". Which means that if someone wrote "*$" when they really meant "*%" their program would appear to work when the base happened to be positive, though with some loss of precision. Point 3: Just what are the syntactic properties of "**"? I have used programming languages where it was left associative, where it was right associative, ones where "a ** -1" was legal, and ones where it wasn't (because unary minus had same precedence as infix -), and ones where "a ** -1" was legal but "a ** -j" was not. I deny that there is a single set of properties which all (or even most) programmers would agree on. Point 4: There is not the slightest reason why an operator should be "more efficient" than functional notation. In BCPL, one writes LET BLOCK = VEC 1000 IN $( statements $) whereas in C one writes { int *block = (int*)malloc(1000 * sizeof *block); statements } Does anyone reading this seriously suppose that the BCPL version is more efficient? Fortran uses functional syntax (MOD, IAND) where C uses operators (%, &). Does anyone seriously suppose that this makes a difference? Point 5: Inline expansion of pow() seems unwise unless the machine has an instruction to support it directly. Even if you have a floating-point chip which provides exp() and ln() instructions, *you should not use them*. To quote Cody & Waite, chapter 7: " The FORTRAN ** operator is defined mathematically as x ** y = exp(y * ln(x)) The obvious implementation of this definition using existing software for the exponential and logarithm functions results in large errors independent of those associated with the elementary function software used. ... The algorithms we present for this computation are far more complicated than any other algorithms presented in this manual." The 80287 and 80387 have "y * log2(x)" and "y * log2(x+1)" instructions, but these should only be used when that is the result you want. Using one of these instructions and then taking exp() is pretty much the combination Cody & Waite warn against. (These operations may use sufficient extra internal precision that you can get away with it, but I'd advise you to run the test program at the end of chapter 7.) This is not, of course, an argument against using an operator. The point is that pow() is a costly operation, which is going to be implemented as a subroutine on almost any existing machine, so why not be honest about it? Point 6: Not only is pow() costly, it is very rarely used even in number crunching programs. The saving is at best |pow(_,_)| - |_**_| = 4 characters. For this we should change the language? rtp() is another matter. But even that is pretty rare. I have some experience with numerical packages written in Fortran, and float**int was just not a common operation. In fact, I would claim that it is sufficiently rare that using a name for it rather than some exotic sequence of characters would make the code *more* readable and *more* maintainable. I wonder why no Pascal admirers have pointed out that Pascal *does* have a notation for what is far the commonest case, namely SQR(expr) = (expr)**2 Mind you, that is a very bad name for the operation, but it does exist. Given that the X3J11 is *standardising* C, not *inventing* it, leaving the two exponentiation operators out is the right thing for them to do. But we really should have the rtp() *operation* as well as pow().