Path: csiph.com!news.mixmin.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: iso646.h Date: Thu, 25 Jan 2024 10:48:11 -0800 Organization: None to speak of Lines: 99 Message-ID: <87le8d45ck.fsf@nosuchdomain.example.com> References: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: dont-email.me; posting-host="25cdfcf079fd064704ce92ded0c098b3"; logging-data="2550163"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19yolXEfpBwNeI+E7SgI+/A" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:QYRaCeELJxDxDiBoBzgKXUTs3IM= sha1:/gR+8lwbKI+nnCjK3ZF9nDNydxw= Xref: csiph.com comp.lang.c:380931 David Brown writes: > On 24/01/2024 20:33, Malcolm McLean wrote: >> On 24/01/2024 13:54, David Brown wrote: [...] >>> Exponentiation is not particularly common in programming, except >>> for a few special cases - easily written as "x * x", "x * x * x", >>> "1.0 / x", or "sqrt(x)", which are normally significantly more >>> efficient than a generic power function or operator would be. >>> >> It's pretty common in the sort of programming that I do. But this is >> fair point. A lot of programs don't apply complex transformations to >> data in the way that mine typically do. > > Different tasks have different programming needs. > >>> That is not an argument against having an operator in C called >>> "pow". It is simply not useful enough for there to be a benefit in >>> adding it to the language as an operator, when it could (and was) >>> easily be added as a function in the standard library. >>> >>> (It could not have been added as "**", because - as Keith said in >>> another post - "x ** y" already has a meaning in C.  While I >>> believe it would be possible to distinguish the uses based on the >>> type of "y", other than for the literal 0, having "x ** y" mean two >>> /completely/ different things depending on the type of "y" would >>> not be a good idea for C.) >>> >> Yes, ** and ^, which are the two common ASCII fallbacks, are already >> taken. But as you said earlier, in reality most exponentiation >> operations are either square or cube, or square root. And in C, that >> means either special functions or inefficiently converting the >> exponent into a double. If pow were an operator, that wouldn't be an >> issue. > > It could certainly still be an issue - it depends entirely on how that > operator were specified, and how it were implemented. > > Unlike normal C functions, operators in C can be "overloaded" by > type. But if there were a "pow" operator that fitted with the style of > existing C operators, we would have overloads for "T pow T to T", > where "T" is an integer type (of rank at least that of "int"), or a > floating point type. We would not see the kinds of overloads that > would actually be useful beyond what you get with today's "pow" > function, such as raising floating point numbers to an integer type. > We would certainly not see efficient shortcuts for common cases at the > standards level (though implementations could do what they wanted). If C added an exponentation operator (let's say "^^"), there's no reason it couldn't distinguish between integer and floating-point exponents. For the "*" operator, the "usual arithmetic conversions" are performed on the operands; this converts them to the same type. There is no integer*floating multiplication operation. For the "<<" and ">>" operators, there's no need for the operands to be of the same type. Only the "integer promotions" are performed on each operand separately, converting narrow integer types to int or unsigned int. Similarly, there's no need for the operands of an exponentiation operator to have the same type. For a hypothetical "^^" exponentation operator, I suggest that: - Each operand can be of either integer or floating type. - An operand that is of integer type has the integer promotions applied to it (promoting narrow integers to int or unsigned int). - If the right operand is of integer type, the semantics are defined in terms of repeated multiplication, followed by taking the reciprocal if the right operand is negative. - 2 ** 3 == 8 - 2.0 ** 3 == 8.0 - 2.0 ** (-3) == 0.125 - 2 ** (-3) == 0 (since 1/8 == 0 in integer arithmetic). - If the left operand is of integer type and the right operand is of floating type, the left operand is promoted to a floating type (perhaps the type of the right operand). - If the right operand is of floating type, the semantics are defined as something like exp(log(x) * y), or perhaps something with better mathematical behavior. Thus x^^2 would be a reasonably subsitute for x*x, and could be expected to perform just as well if the right operand is a constant. Complex and imaginary types add another layer of *ahem* complexity that I've ignored here. As for the operator symbol, a new "pow" keyword (`x pow y`) would have been fine if it had been added in the 1980s, but it would conflict with the existing pow() function from and break existing code. I suppose the keyword would have to be _Pow, but that's ugly enough that I prefer "^^". Again, there's probably not enough demand to make it likely to appear in a future C standard, but that doesn't stop me from having ideas of what it should look like if it is added. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Medtronic void Void(void) { Void(); } /* The recursive call of the void */