-
Notifications
You must be signed in to change notification settings - Fork 483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exponentiation primop #6390
Comments
@kwxm I think you were going to respond to this one? I'll triage it afterwards. |
@kwxm a gentle reminder. |
We've considered adding an integer exponentiation in the past but decided against it for a number of reasons.
It is plausible that calculating powers of two might be something that people might particularly want to do, but this may be more feasible now that we have the recently-added bytestring builtins, and will become evenmore feasible if we get more efficent integer/bytestring conversions once we've moved on from GHC 8.xx. Also, we're currently adding a modular exponentiation builtin, and careful use of that with a large modulus would be another way to calculate standard integer powers. (Note also that if we ever do want a normal exponentiation function we could perhaps include it in Another issue is that it's difficult to take account of special cases in costing: we have to cost the worst case of builtin evaluations, so if some case such as calculating a power of 2 can be implemented particularly efficiently, we'd still have to charge for the non-optimal case: the function might run more quickly in certain cases, but this wouldn't be reflected in the charges paid by the user. Given these issues we feel that there's probably not a compelling case for adding integer exponentiation at this time. If there's sufficient community demand then we might revisit this in the future. |
I'm not sensing a definite "won't do" here, so I'm going to retriage this as "Low priority" (and "won't do" is better known as closing the issue anyway).
I think from the implementation point of view this should be fairly straightforward, want me to provide a proof-of-concept? From the spec point of view it's gonna be hard, I'm sure. |
Not really! I think it'd be problematic because we'd have to match up special cases in the costing with special cases in the implementation and keep them synchronised. We already do a certain amount of this kind of thing and it's a bit annoying. You also have to add extra logic to detect the special case before you call the function, which will add extra overhead. In addition we'd need different sets of costing benchmarks for the different special cases, and again these would have to be kept in sync with the implementation. |
OK, yes, that's what I foolishly called "fairly straightforward". Given some additional feedback elsewhere, it seems like my original assessment of this not being a "won't do" is wrong. I'm closing the issue then, we'll reopen it if ever want to reconsider adding such a builtin. @kozross thank you for the report and sorry we aren't able to fulfill your request. |
Describe the feature you'd like
This is a follow-on from #6335, and relates to prior requests in #4168 and here, as well as #6344 (as it used exponentiation, both modular and not, internally).
Currently, if you want exponentiation, you have to resort to exponentiation by squaring. While for arbitrary semigroups (or monoids, or groups), this is indeed the best we can do, in the specific case of
BuiltinInteger
(which is ultimately what is interesting to us here), we lose considerably. Thus, we propose that a builtin non-modular exponentiation operation be added, allowing us to provide this functionality efficiently, while also answering some community requests for functionality.Firstly, even if we just compare a typical exponentiation-by-squaring implementation to Haskell's built-in
^
forInteger
, we see we're falling behind, even on small numbers:This would only become more of a problem the larger the numbers become.
Secondly, there are notable optimization paths we could take. Firstly, there is the classic case where raising 2 to a positive power is in fact a shift. This is not an optimization GHC seems to perform for
Integer
at least:We also noticed that if we know an exponent is an exact power of two, regardless of base, we could beat exponentiation:
We can use both of these facts to gain significant advantage on
Integer
exponentiation by making further observations:These optimizations require low analysis costs (a trailing zero count effectively), and would work for most inputs (assuming a completely random choice of base or exponent). Further than this, if we were to implement a non-modular exponentiation operation directly, a future move away from GHC 8.10 would permit us to implement this operation mutably (requiring the new
ghc-bignum
interface), which would significantly improve our performance by requiring only one up-front allocation for the result.This operation would not only answer these (in some cases long-standing) concerns, but also optimize a useful operation.
Describe alternatives you've considered
The current options consist of either:
The first has the inefficiencies we described, while the second unfortunately is drowned out by the fact that CIP-121 conversions are currently quadratic, and even with
ghc-bignum
's interface, cannot be made better than linear due to pinning issues. Both of the issues linked above essentially make this point, as in their use cases, these inefficiencies are unacceptable.The text was updated successfully, but these errors were encountered: