I noticed that the exponentiation operator of a param to a param power is a not a param operation. I will see what I can do to rectify this at some stage if others think it worthwhile.
While it is obvious from the documentation that the operator returns a const, it might be clearer if it says explicitly that it does not work in a param expression.
I think it would be reasonable to request that param**param => param. At least, I don't know of a reason offhand that we don't support it or wouldn't—I suspect it's more a case that nobody needed or implemented in the early days that perhaps hasn't been discussed or noticed until now.
I do see these param overloads for integral types. Maybe what you are asking for is specifically about reals? And this seems to be where we we would have to put in some implementation to support compile-time exponentiation of reals.
inline operator **(param a: real(?w), param b: integral) param where b == 1
{
return a;
}
inline operator **(param a: real(?w), param b: integral) param where b == 2
{
return a * a;
}
// the next two are only exact when a is an exact power of 2.0 (a common occurrence)
inline operator **(param a: real(?w), param b: integral) param where b == (-1)
{
return 1 / a;
}
inline operator **(param a: real(?w), param b: integral) param where b == (-2)
{
return 1 / (a * a);
}
Yes, I believe this should work where if the exponent is one of {-2, -1, 1, 2} you'll get a compile-time operation. Otherwise, none of these operators will resolve and the compiler will fall back to doing an execution-time operation.
Thanks for the additional information, @damianmoz.
My thought here would be to implement param real**param ? as a primitive in the compiler in the most straightforward way for generality, but then to potentially have strength-reduced cases like Damian's in the module code to handle cases that are common and optimizeable. @e-kayrakli, is that what you're thinking as well?
I was impressed at how easy it was to implement and at how much more readable the code becomes.
At some stage I will contribute the code to allow accurate x**n whre x is real(w) and n any integer and the result is accurate to at worst twice the error as that of x**2. It is a Chapel implementation of an algorithm from ACM TOMS. I wrote it a few months ago but never finished the QA on the testing. I got distracted by my day job. It does demand an fma() routine but that got done a while ago.
Damian, if you're up for it, I think it'd be helpful to have you open a GitHub issue requesting that ** support param implementations for a real base (and you can make the call whether you'd like it just support int[egral] exponents or real as well—FWIW, I imagine that supporting both would not be difficult).
Mostly. If we were to put in that compiler-based implementation (we should), I wouldn't put strength-reduced versions in the module code, I think. I'd prefer all compile-time operations under the same umbrella to be in the same place in the implementation. What advantage do you see in having these "overloads" in the module code?
Oh, that's a great point. I was thinking "efficiency", but as a very sloopy mode of thinking since that's arguably not as important for a param implementation as it is for execution-time code. And of course, a primitive may actually be faster (or similarly fast as) an optimized module-based implementation anyway(?) Or, more likely, however long either implementation takes, it won't be the bottleneck in computation anytime soon. So yeah, a single primitive implementation definitely seems simpler and sufficient.