-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[SE-0288] [stdlib] Adding isPower(of:) to BinaryInteger #24766
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
base: main
Are you sure you want to change the base?
Conversation
The idea of this implementation is based on a fast-/slow-path pattern. We have a generic implementation, which is suitable for all inputs, as the slow path; and meanwhile provide some particularly optimized implementation for frequently used inputs (e.g., 2 and 10) as the fast paths. Some experiments (code can be found here) are conducted to compare the performance of different scenarios, including:
The tables below show the execution time (in sec) for three different types of integers under the Table 1. The built-in
Table 2. Prototype DoubleWidth (with Int 256-bit width)
Table 3. Prototype BigInt (with 1024-bit width)
It can be seen that:
The conclusion is the fast-/slow-path pattern is a good fit for implementing this API, given that it happens much more often to check if a number is a power of some popular bases (e.g., 2, 10) than others. |
No optimization for bases that are a power of 2? |
Thanks for pointing this out, Michel~ I have put this together and |
d157582
to
ea6727a
Compare
Following @stephentyrone 's advice, I had |
642b553
to
5644c42
Compare
As per the feedbacks from the community, I had the public API |
62095c4
to
14c18be
Compare
@shahmishal Thanks for the information, Mishal! I had the base branch changed to @jckarter Hi Joe, I rebased this PR; and added some minor comment, as you suggested in the evolution review, for better clarification purpose. Would you take a look at it and fire a test, please? |
@swift-ci test |
@swift-ci Please test source compatibility |
stdlib/public/core/Integers.swift
Outdated
if base.magnitude <= 1 { return self == base } | ||
|
||
// At this point, we have base.magnitude >= 2. Repeatedly perform | ||
// multiplication by a factor of base, and check if it can equal self. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment here doesn't match the implementation. Please update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
Thank Stephen and Ben for your inputs! I had the comments updated. |
@swift-ci Please test |
@swift-ci Please test source compatibility |
This PR adds a public API 'isPower(of:)', as an extension method, to the 'BinaryInteger' protocol. It checks if an integer is power of a given base. Resolves: SE-0288
Thank you for your help, Ben! I had the PR rebased with commits squashed. |
@swift-ci Please smoke test |
let (bound, remainder) = self.quotientAndRemainder(dividingBy: base) | ||
guard remainder == 0 else { return false } | ||
|
||
// Return true if the product eventualy hits bound. Because if bound is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Return true if the product eventualy hits bound. Because if bound is | |
// Return true if the product eventually hits bound. Because if bound is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch, Matt~
So basically this looks fine to me, except for a weird process detail: during the time period between when this proposal was written and when the SE approval actually ran, Swift Preview was introduced and the process changed, meaning that this feature should actually land first in Swift Preview rather than directly in the standard library. It's annoying because while Swift Preview is supposed to decrease the workload for proposals, it increases it for things that happen to have been inflight while the process moved under them. My apologies for that. Please reach out to me and @natecook1000 if you need any assistance in creating a PR against preview. |
This patch implements SE0288 in the swift evolution staging repository. The corresponding pull request against the main Swift repository is swiftlang/swift#24766.
@stephentyrone Thanks for pulling this work on the right track, Stephen! I created a PR against the As for the |
@natecook1000 Can you clarify the process for @dingobye? |
@dingobye There's one other thing we should resolve (which I should have flagged in the proposal review, but missed). Instead of the existing signature:
this method should be:
This is a fairly trivial change, but will allow us to avoid creating a bignum object in the case where Self is an arbitrary-precision (or even just large, e.g. Int128 or bigger) integer and base is small. Formally, this requires another evolution proposal, but it can be quite perfunctory, and I'm happy to help write the proposal. I think you should go ahead and adopt this change for your preview package, and we'll get review started as soon as we can. |
@stephentyrone Hi Stephen, I updated the PR against the staging repo here as per your advice. In fact, I took some time thinking about the function signature at the very beginning when pitching this idea. After browsing the existing functions in standard library, I made the decision to use
Pros of using
Cons of using
I don't mind going through review process, since the public function signature is so important to ABI. Not sure if it is really worth the change. Would like to hear more of your inputs. |
Well, no, because we also have
random(in:) and quotientAndRemainder(dividingBy:) are primarily used in ways that make it so that having them be generic makes a lot less sense, so those are fine as is. |
If we check its implementation, it turns rhs to Can we revise SE-0288 for a 2nd round review, without having to prepare a separate proposal? If it works, would you help revise the proposal and staging repo's implementation to make it armed for a 2nd round review? BTW, don't forget to remove the first acknowledgement item when adding your name into the author list. I've already owned you too much on this story, and you are well deserved. Thank you~ |
This patch implements SE0288 in the swift evolution staging repository. The corresponding pull request against the main Swift repository is swiftlang/swift#24766.
Is this PR still live? Or has it been supplanted by a PR to the Preview repo? |
} | ||
} | ||
|
||
/// Returns `true` iff `self` is a power of the given `base`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔨
/// Returns `true` iff `self` is a power of the given `base`. | |
/// Returns `true` if `self` is a power of the given `base`. |
This PR presents the implementation of adding a public API
isPower(of:)
to theBinaryInteger
protocol.