December 17, 2019
On Tuesday, 17 December 2019 at 15:07:40 UTC, Dominikus Dittes Scherkl wrote:
> If you look at it from mathematical point of view:
> pow is defined as a mapping
> ℕ × ℕ → ℕ
> but if we extend it to
> ℤ × ℤ → ℤ
> we have undefined points, because 1/n is not in ℤ for all n>1.

Not sure what you mean. You can construct any algebra you want.
D  has "defined" x/y for integer values as:

(x/y)*y = x - x%y

So integer division in D is defined through modulo y.

That holds if x=1 and y=n ?

(In typical math you would only use multiplication and modulo on integers and simply not define a division operator.)

December 17, 2019
On 17.12.19 16:43, Patrick Schluter wrote:
> On Tuesday, 17 December 2019 at 14:29:58 UTC, Timon Gehr wrote:
>> On 17.12.19 15:02, Patrick Schluter wrote:
>>>
>>> Except for 0^^0 there is no reason to throw or crap out.
>>
>> 0^^0 = 1 and D gets this right already.
> 
> Not as clear cut as you say, but generally it is agreed upon being set to 1.
> 
> https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero
> ...

- Anyone can edit Wikipedia, and laymen like to preserve outdated conventions from 200 years ago that are sometimes taught in primary school.
- That article actually explains why a computer scientist must consider the value to be 1 if your domain of exponents models a discrete set. (Knuth says so!)
- Many other modern programming languages also get it right, even C99.
- D is sometimes proud to fix design mistakes in C++. Add this to the list.

> but to clarify what I meant
> 
> except for 0^0 where an exception could be justified,

It can't be justified. The reason IEEE 754 supports multiple conventions, with 1 being the default, is that floats are often used to approximately model continuous functions and an exact value of 0 could be the result of a rounding error.

> all other cases have no reason to even contemplate throwing an exception.

0^^-1.

December 17, 2019
On 17.12.19 16:44, Jab wrote:
> On Tuesday, 17 December 2019 at 15:08:31 UTC, Timon Gehr wrote:
>> On 17.12.19 15:02, Patrick Schluter wrote:
>>>>>>
>>>>> You are wrong.
>>>> Please no ad hominem attacks!
>>>
>>> That's not an ad hominem. That's just a statement of opinion. It would be ad hominem if something about you was the justification of the wrongness. You're wrong because your name is too long or because you have a big nose etc.
>>
>> Although some people do count disagreeing with mathematically wrong statements as a personal attack:
> 
> Just quoting "I think" with a reply "you are wrong" isn't any better way to run a community. It's not so much that you are disagreeing with it, so much as you don't know how to convey that you are disagreeing with it like a human being.
> ...

You are setting a great example.

>> https://github.com/pandas-dev/pandas/issues/9422#issuecomment-343550192
> 
> So you had to pull an example from close to 3 years ago?
> 

It's the one I am familiar with. I'm not very active in other communities.
December 17, 2019
On Tuesday, 17 December 2019 at 14:02:53 UTC, Patrick Schluter wrote:
[...]
>> 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.
>
> Except for 0^^0 there is no reason to throw or crap out. int.max+1 also doesn't throw and it is also generally a probable bug in the user code.

But 0^^0 in general, is very often replaced by lim x-> 0 x^^x witch is 1.

The question is answered here:

https://stackoverflow.com/questions/19955968/why-is-math-pow0-0-1

...long story but may be this is the point:

"as a general rule, native functions to any language should work as described in the language specification. Sometimes this includes explicitly "undefined behavior" where it's up to the implementer to determine what the result should be, however this is not a case of undefined behavior."

If you look at pow in the cpp.reference language definition, you realize how 'complex' the pow issue becomes...

https://en.cppreference.com/w/cpp/numeric/math/pow
December 17, 2019
On 17.12.19 17:48, Martin Tschierschke wrote:
> On Tuesday, 17 December 2019 at 14:02:53 UTC, Patrick Schluter wrote:
> [...]
>>> 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.
>>
>> Except for 0^^0 there is no reason to throw or crap out. int.max+1 also doesn't throw and it is also generally a probable bug in the user code.
> 
> But 0^^0 in general, is very often replaced by lim x-> 0 x^^x witch is 1.
> ...

0^^0 is 1 because there is one canonical function mapping the empty set to itself. Also, if one really wants a justification involving calculus look no further than Taylor series.

> The question is answered here:
> 
> https://stackoverflow.com/questions/19955968/why-is-math-pow0-0-1
> ...

This is probably the most useful answer: https://stackoverflow.com/a/20376146

> ...long story but may be this is the point:
> 
> "as a general rule, native functions to any language should work as described in the language specification. Sometimes this includes explicitly "undefined behavior" where it's up to the implementer to determine what the result should be, however this is not a case of undefined behavior."
> 
> If you look at pow in the cpp.reference language definition, you realize how 'complex' the pow issue becomes...
> 
> https://en.cppreference.com/w/cpp/numeric/math/pow

This function does not handle integers separately. 0^^0=1 is completely mundane.
December 17, 2019
On 17.12.19 18:09, Timon Gehr wrote:
> On 17.12.19 17:48, Martin Tschierschke wrote:
>> ...
>>
>> https://en.cppreference.com/w/cpp/numeric/math/pow
> ...

Haha. pow(0.0,0.0) is either 1.0 or NaN, but pow(1.0,∞) is guaranteed to be 1.0.

So I guess the C++ standards committee considers the base a pristine value from ℝ while the exponent is rounded floating-point garbage. I wonder how much thought they actually put into this. I also wonder if there are any implementations who indeed choose to deviate from the floating-point standard. (GNU C++ evaluates pow(0.0,0.0) as 1.0).
December 17, 2019
On Tuesday, 17 December 2019 at 13:30:48 UTC, Timon Gehr wrote:
> [snip]
>
> 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.


On Tuesday, 17 December 2019 at 13:11:35 UTC, Timon Gehr wrote:
> [snip]
>
> 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
> }

I think these are both really good points*. If constant folding weren't being removed, I wouldn't have a strong feeling on this, but I think it is probably important to prevent the regression.

The current behavior clearly has some compiler magic going on before this recent change to constant folding. In some sense, you would be enshrining this "special" behavior so that
writeln((2)^^(-1)); //compiler error
writeln((2)^^(-2)); //compiler error
writeln((-2)^^(-1)); //compiler error
writeln((-2)^^(-2)); //compiler error
would no longer be errors and would print 0. After thinking on it, it probably makes sense to make these changes for language consistency. I'm certainly the type of person who could get tripped up by these changes, but it still is starting to make sense to me.

Can anyone remind me again why ^^ depends on a phobos function?

* Your example with x^^-1 is perhaps overblown as an issue because ^^-1 works through constant folding, if you make it enum int x = -1, then it's not an error.
December 17, 2019
On Tuesday, 17 December 2019 at 17:31:41 UTC, Timon Gehr wrote:
> Haha. pow(0.0,0.0) is either 1.0 or NaN, but pow(1.0,∞) is guaranteed to be 1.0.

The limits for 0^0 does not exist and floating point does not represent exactly zero, but approximately 0.

December 17, 2019
On Tuesday, 17 December 2019 at 16:48:42 UTC, Martin Tschierschke wrote:
> But 0^^0 in general, is very often replaced by lim x-> 0 x^^x

Well, but if you do the lim of x^^y you either get 1 or 0 depending on how you approach it.

December 17, 2019
On Tuesday, 17 December 2019 at 18:41:01 UTC, Ola Fosheim Grøstad wrote:
> On Tuesday, 17 December 2019 at 17:31:41 UTC, Timon Gehr wrote:
>> Haha. pow(0.0,0.0) is either 1.0 or NaN, but pow(1.0,∞) is guaranteed to be 1.0.

Besides, that is not what it said on the page. It said that 0^0 may lead to a domain error. Which is reasonable for implementors, but it also referred to IEC60559 which set x^0 to 1.0 even if the base is NaN.

The goal of ISO standards is to codify and streamline existing practices for better interoperability, C++ is an ISO standard.