December 16, 2019
On Monday, 16 December 2019 at 06:44:31 UTC, Dominikus Dittes Scherkl wrote:
> [...] And if its time critical and you need only integers, there are much faster solutions than using pow (e.g. odd(x)?-1:1 )

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. As Timon explained, the restriction just makes no sense and was not what he had expected (I am also very surprised by this). I admit that Timon’s explanations sounded a bit harsh, but that does not makes them any less true. This is simply an arbitrary limitation. The definition of pow in math can be perfectly adapted to integers by simply using integer division, i.e. 2^^(-1) == 0, so this is how it should work.
December 16, 2019
On Monday, 16 December 2019 at 12:25:11 UTC, Johannes Loher wrote:
> On Monday, 16 December 2019 at 06:44:31 UTC, Dominikus Dittes Scherkl wrote:
>> [...] And if its time critical and you need only integers, there are much faster solutions than using pow (e.g. odd(x)?-1:1 )
>
> 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. As Timon explained, the restriction just makes no sense and was not what he had expected (I am also very surprised by this). I admit that Timon’s explanations sounded a bit harsh, but that does not makes them any less true. This is simply an arbitrary limitation. The definition of pow in math can be perfectly adapted to integers by simply using integer division, i.e. 2^^(-1) == 0, so this is how it should work.

As mentioned by both Timon and Johannes, in mathematics, and especially in combinatorics, the usage of (-1)^^i for natural number i is extremely common. For example, the definition of a determinant of a matrix uses this concept. Also, the binomial expansion of (a-b)^n can be elegantly expressed using (-1)^i. In general, any computation where the sign depends on the parity of a number i can be expressed using (-1)^i. (Another example would be the inclusion-exclusion principle for expressing the size of the union of k sets).

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

I'm a little confused by this thread...

1) the bug report is about a function taking an int and an int. Just focusing on the math, the result of the function with a negative exponent would be a float. So, it makes perfect sense for the function to prevent this when dealing with ints only. Just cast part of it to float and you get the right result.

2) I'm so confused by why everyone is bringing up (-1)^^i.
a) i normally represents sqrt(-1) in math, so that's a complex number...the overload deals with ints. You should be concerned by an overload for complex numbers.
b) This conversation would make a little more sense is if we are considering i as a member of the set (0, 1, 2, 3, ...). In which case, the value is still a complex number most of the time. IMO, people concerned with this case should cast -1 to complex and then call pow.

3) In math, we have different types of numbers: natural numbers, rational numbers, real numbers. Just because a formula has a defined result for every value of complex numbers, doesn't mean that is the case for the other types of numbers. Computer science types, like int and float, have some analog in math numbers, but they aren't the same thing. I think you'll get confused when trying to think they are the exact same thing.
December 16, 2019
On Monday, 16 December 2019 at 13:20:58 UTC, jmh530 wrote:
> On Monday, 16 December 2019 at 12:39:11 UTC, M.M. wrote:
>> [snip]
>>
>> As such, (-1)^^i is _extremely_ useful and common, and changing how (common) math works in a programming language is asking for troubles.
>
> I'm a little confused by this thread...
>
> 1) the bug report is about a function taking an int and an int. Just focusing on the math, the result of the function with a negative exponent would be a float. So, it makes perfect sense for the function to prevent this when dealing with ints only. Just cast part of it to float and you get the right result.
>
> 2) I'm so confused by why everyone is bringing up (-1)^^i.
> a) i normally represents sqrt(-1) in math, so that's a complex number...the overload deals with ints. You should be concerned by an overload for complex numbers.
> b) This conversation would make a little more sense is if we are considering i as a member of the set (0, 1, 2, 3, ...). In which case, the value is still a complex number most of the time. IMO, people concerned with this case should cast -1 to complex and then call pow.
>
> 3) In math, we have different types of numbers: natural numbers, rational numbers, real numbers. Just because a formula has a defined result for every value of complex numbers, doesn't mean that is the case for the other types of numbers. Computer science types, like int and float, have some analog in math numbers, but they aren't the same thing. I think you'll get confused when trying to think they are the exact same thing.

In my comment, "i" stands for an iterator (in a for-loop, for example), and not for a complex number.

But I also see that my answer stressed the usefulness of (-1)^i for the cases where i is a _positive_ integer, which is not the part of this discussion.

So, while determinants or binomial coefficients do not use naturally (-1)^i with negative value of i, there are other cases (which Timon probably referred to) in combinatorics, where using (-1)^i with negative value comes naturally.

December 16, 2019
On Monday, 16 December 2019 at 13:53:06 UTC, M.M. wrote:
> So, while determinants or binomial coefficients do not use naturally (-1)^i with negative value of i, there are other cases (which Timon probably referred to) in combinatorics, where using (-1)^i with negative value comes naturally.

It is easy to implement, isn't it?
But what would you optimize for?

Would you make x^i = 0  a bit faster for i < 0  in the general case?
Or would you test for -1 and special case it for significant speedups?

Without special casing it will be slow:

(-1)^(-1) = 1/((-1)^1 ) = -1
(-1)^(-2) = 1/((-1)^2) = 1
(-1)^(-3) = 1/((-1)^3) = -1

With special casing you get: 1 - ((i&1)<<1) or something like that.
(1-2 and 1-0)
December 16, 2019
On Monday, 16 December 2019 at 13:53:06 UTC, M.M. wrote:
> [snip]
>
> In my comment, "i" stands for an iterator (in a for-loop, for example), and not for a complex number.
>
> But I also see that my answer stressed the usefulness of (-1)^i for the cases where i is a _positive_ integer, which is not the part of this discussion.
>
> So, while determinants or binomial coefficients do not use naturally (-1)^i with negative value of i, there are other cases (which Timon probably referred to) in combinatorics, where using (-1)^i with negative value comes naturally.

I don't doubt that (-1)^i, where i is an iterator, is useful in many, many cases. However, you would need for pow(int, int) to return a complex number all the time, if you want to handle that use case, not just when i<0. That will make a lot of other code a lot more complicated. It is much simpler to convert -1 to complex and then call pow(complex, int) and return a complex number. That means that whether i=1 or i=2, the result is complex. That will make your life a lot less complicated, particularly if you pass that result to other functions.
December 16, 2019
On Monday, 16 December 2019 at 15:00:47 UTC, jmh530 wrote:
> 
>
> I don't doubt that (-1)^i, where i is an iterator, is useful in many, many cases. However, you would need for pow(int, int) to return a complex number all the time, if you want to handle that use case, not just when i<0. That will make a lot of other code a lot more complicated. It is much simpler to convert -1 to complex and then call pow(complex, int) and return a complex number. That means that whether i=1 or i=2, the result is complex. That will make your life a lot less complicated, particularly if you pass that result to other functions.

What I mean is that if i is 0.5, then you have to return a complex. So you have to add a special case for that.
December 16, 2019
On Monday, 16 December 2019 at 15:13:44 UTC, jmh530 wrote:
> [snip]
>
> What I mean is that if i is 0.5, then you have to return a complex. So you have to add a special case for that.

Simple work-around for the (-1)^^i:

import std;

void main() {
    auto x = iota(10).map!(a => a % 2 ? 1 : -1);
}

December 16, 2019
On Monday, 16 December 2019 at 15:33:33 UTC, jmh530 wrote:
> On Monday, 16 December 2019 at 15:13:44 UTC, jmh530 wrote:
>> [snip]
>>
>> What I mean is that if i is 0.5, then you have to return a complex. So you have to add a special case for that.
>
> Simple work-around for the (-1)^^i:
>
> import std;
>
> void main() {
>     auto x = iota(10).map!(a => a % 2 ? 1 : -1);
> }

Why can't that pow(int, int) function implement that workaround and return 0 on all negative exponents and not crash otherwise?
That a function balks at mathematically nonsense values like 1/0 or 0^^0 ok, it's expected. That it does so on a function that mathematically has valid parameters (even if the result can not be represented) is not normal. Nobody expects 2^^70 to crash with divide by 0 error unless explicitly requesting checked integers that catch overflows.
December 16, 2019
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?
> That a function balks at mathematically nonsense values like 1/0 or 0^^0 ok, it's expected. That it does so on a function that mathematically has valid parameters (even if the result can not be represented) is not normal. Nobody expects 2^^70 to crash with divide by 0 error unless explicitly requesting checked integers that catch overflows.

I think I made some mistakes earlier because I kept mixing stuff up. Particularly because an exponent of 0.5 wouldn't matter with ints.

It wouldn't return 0 on all negative exponents. For -2 and more negative, it should return always 0. For -1, it would return zero if x is -2 or smaller and otherwise 1 or -1 depending on whether the exponent is odd or even.