December 16, 2019
On Monday, 16 December 2019 at 12:39:11 UTC, M.M. wrote:
[...]
> As such, (-1)^^i is _extremely_ useful and common, and changing how (common) math works in a programming language is asking for troubles.

!!! +1
December 16, 2019
On Monday, 16 December 2019 at 15:33:33 UTC, jmh530 wrote:
> void main() {
>     auto x = iota(10).map!(a => a % 2 ? 1 : -1);
> }

xor or unrolling would be faster. I wouldn't trust a compiler on that one.
December 16, 2019
On Monday, 16 December 2019 at 17:07:42 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 16 December 2019 at 15:33:33 UTC, jmh530 wrote:
>> void main() {
>>     auto x = iota(10).map!(a => a % 2 ? 1 : -1);
>> }
>
> xor or unrolling would be faster. I wouldn't trust a compiler on that one.

To explain, in case that was a bit brief (8 bit case):

-1 = 11111111
1   = 00000001

So all you have to do is xor with

~1 = 11111110


December 17, 2019
On Monday, 16 December 2019 at 15:57:13 UTC, jmh530 wrote:
> On Monday, 16 December 2019 at 15:49:35 UTC, Patrick Schluter wrote:
>> [snip]
>>
>> Why can't that pow(int, int) function implement that workaround and return 0 on all negative exponents and not crash otherwise?

I still don't understand why anybody want a function with signature

int pow(int, int)

I think there are only two interesting cases:

int pow(int, ubyte)

and

complex pow(complex, complex)

both working correct for any possible input, but of course the integer version is likely to overflow even for relatively small exponents. To make this more prominent for the user, I would only allow 8bit exponents anyway. If you call it with something sensible, the exponent should fit that, else the result will be some garbage anyway. Same with negative exponents - rounding away any bit of information from the result is just an offense. Why offer such nonsense? Anybody interested in using pow with negative exponents cannot be interested in an interger result.

maybe (for performance reasons?)

real pow(real, real)

would also be of interest, but there are (strange) constraints to when the result is real, so I cannot really recommend this. In fact for an negative integral exponent n there are n solutions of which only one is real (or two if n is even).
So the signature would better be

real pow(real x, real e) in(e>=0)

But I would always prefer the two cases without constraints.

December 17, 2019
On 17.12.19 13:03, Dominikus Dittes Scherkl wrote:
> On Monday, 16 December 2019 at 15:57:13 UTC, jmh530 wrote:
>> On Monday, 16 December 2019 at 15:49:35 UTC, Patrick Schluter wrote:
>>> [snip]
>>>
>>> Why can't that pow(int, int) function implement that workaround and return 0 on all negative exponents and not crash otherwise?
> 
> I still don't understand

Please read the entire thread.

> why anybody want a function with signature
> 
> int pow(int, int)
> ...

You are apparently not aware that std.math.pow is the implementation of the built-in `^^` operator. Removing it is not even on the table, it should just work correctly.

> I think

You are wrong.

> there are only two interesting cases:
> 
> int pow(int, ubyte)
>  > and
> 
> complex pow(complex, complex)
> ...

Those cases already work fine, and they are off-topic. The bug report is for an existing feature that does not work correctly.

> both working correct for any possible input, but of course the integer version is likely to overflow even for relatively small exponents.

As I am stating for the third time now, there are x such that `pow(x,int.max)` and/or `pow(x,int.min)` neither overflow nor cause any rounding.

> To make this more prominent for the user, I would only allow 8bit exponents anyway.

I am the user in question and I am not a moron. Thanks a lot.

> If you call it with something sensible, the exponent should fit that, else the result will be some garbage anyway. Same with negative exponents - rounding away any bit of information from the result is just an offense. Why offer such nonsense? Anybody interested in using pow with negative exponents cannot be interested in an interger result.
> ...

I really don't understand the source of those weird `pow`-related prejudices. You are the one who is spewing nonsense.

This is such a trivial issue. This shouldn't be this hard.

December 17, 2019
On 16.12.19 13:25, Johannes Loher wrote:
> I admit that Timon’s explanations sounded a bit harsh

I reported an obvious issue. It's really a no-brainer, but some people somehow feel the need to intervene and argue in favour of the trivially wrong behavior (this is an issue of basic arithmetic), calling my precious code nonsensical or trying to argue that I must not be aware that built-in integer types have finite precision, etc.

I think a bit of harshness is well-justified, as if those people had spent just 5 to 10 minutes actually thinking, they wouldn't find themselves on the wrong side of this argument and wouldn't feel the need to further defend an opinion born out of some strange irrational bias.
December 17, 2019
On 16.12.19 16:33, jmh530 wrote:
> On Monday, 16 December 2019 at 15:13:44 UTC, jmh530 wrote:
>> [snip]
>> ...
> 
> Simple work-around for the (-1)^^i:
> 
> import std;
> 
> void main() {
>      auto x = iota(10).map!(a => a % 2 ? 1 : -1);
> }
> 

Yes, of course. The expression (-1)^^i is even special-cased by DMD so it can actually be used. Does this mean pow(-1,-1) should cause a divide by zero error? Of course not.

Just to elaborate on how ridiculous the current behavior is:

import std.math;

void main(){
    int x=-1;
    writeln((-1)^^(-1)); // ok, writes -1
    writeln(pow(-1,-1)); // divide by zero error
    writeln((-1)^^(-2)); // ok writes 1
    writeln(pow(-1,-2)); // divide by zero error
    writeln(x^^(-1));    // compile error
    writeln(pow(x,-1));  // divide by zero error
    writeln((-1)^^x);    // ok, writes -1
    writeln(pow(-1,x));  // divide by zero error
    writeln(x^^x);       // divide by zero error
    writeln(pow(x,x));   // divide by zero error
}
December 17, 2019
On Sunday, 15 December 2019 at 18:31:14 UTC, Timon Gehr wrote:
> On 15.12.19 19:22, berni44 wrote:
>>
>> What do you think about this?
>> 
>> [1] https://issues.dlang.org/show_bug.cgi?id=7006
>
> A negative exponent should behave like a negative exponent. I.e., a^^-1 = 1/a. There's no good reason to do anything else.

+1

There's no grey area IMO. Mathematically pow is defined for negative exponents, even if almost all the time the result would be truncated to zero when computing an integer result, that's what it should do.

December 17, 2019
On 16.12.19 13:25, Johannes Loher wrote:
> 
> The thing is: In math, it is extremely common to write this as (-1)^^x. I don‘t understand why we should not allow this notation.

Note that in existing compiler releases, the specific notation (-1)^^x is currently supported as a special rewrite rule in the frontend. This is going away though: https://github.com/dlang/dmd/commit/0f2889c3aa9fba5534e754dade0cae574b636d55

I.e., I will raise the severity of the issue to regression.
December 17, 2019
On Tuesday, 17 December 2019 at 12:31:15 UTC, Timon Gehr wrote:
>> I still don't understand
>> why anybody want a function with signature
>> 
>> int pow(int, int)
>> ...
>
> You are apparently not aware that std.math.pow is the implementation of the built-in `^^` operator. Removing it is not even on the table, it should just work correctly.

Did I suggest to remove it? NO.
But I'm of the opinion that having each internal operator returning the same type as the given types is not always useful.
^^ should result in a real if the exponent is outside ubyte range.
Is this wrong? Am I crazy?

Ok, this would be a huge language change, so I agree.
giving x^^negative_exp == 0 is something we could do.

>> I think
> You are wrong.
Please no ad hominem attacks!

>
>> there are only two interesting cases:
>> 
>> int pow(int, ubyte)
>>  > and
>> 
>> complex pow(complex, complex)
>> ...
>
> Those cases already work fine, and they are off-topic.
No, they do not work fine, because an implausible input range for the exponent is defined.
I still think this should be fixed.

> As I am stating for the third time now, there are x such that `pow(x,int.max)` and/or `pow(x,int.min)` neither overflow nor cause any rounding.
Yes, the cases with x == -1, 0 or 1. And only them.
Maybe it should be fixed for these cases, for those who insist to use the operator instead of some very fast bit-muggling if they need a toggling function.

>> To make this more prominent for the user, I would only allow 8bit exponents anyway.
>
> I am the user in question and I am not a moron. Thanks a lot.
I didn't say that. Don't lay words into my mouth.

> This is such a trivial issue. This shouldn't be this hard.
It's not hard. But there are a lot of cases where giving a negative exponent is NOT intended, and maybe it is a better idea to throw to indicate misuse instead of rounding away all information by returning 0? (except for the three special cases where I already agreed treating them correct would be a win).

To summarize:
If we need to stay with int ^^ int == int, I vote NOT to return 0 for negative exponent and still throw, except for the three special cases, where the correct result should be given.