-
Notifications
You must be signed in to change notification settings - Fork 363
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
Added Fast Power in Number Theory #76
Conversation
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.
It would be great if you also add tests for this, similar to the ones found here. Let me know if you need more information regarding it.
NumberTheory/FastPower.cpp
Outdated
#include <iostream> | ||
|
||
using namespace std; | ||
typedef long long ll; |
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.
Use unsigned long long
for double the range.
NumberTheory/FastPower.cpp
Outdated
typedef long long ll; | ||
|
||
//Function that returns x raised to the power of y | ||
ll fastPower (ll x,ll y) |
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.
Please use more meaningful variable names like base
and exponent
instead of just x
and y
.
Also, rename the function to fast_power
to adhere to the guidelines.
NumberTheory/FastPower.cpp
Outdated
@@ -0,0 +1,47 @@ | |||
/* | |||
<Fast Power> |
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.
Please remove the angle brackets (<
and >
) and indent the block by one level (4 spaces).
NumberTheory/FastPower.cpp
Outdated
|
||
cin>>base>>power; | ||
|
||
cout<<fastPower(base,power); |
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.
Add a trailing "\n"
so that the prompt on terminals is displayed in the next line.
NumberTheory/FastPower.cpp
Outdated
|
||
Space Complexity | ||
------------------ | ||
O(log(N)) where N is the power the number is raised to. |
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.
where N is the power the number is raised to
More simply, where N is the exponent.
NumberTheory/FastPower.cpp
Outdated
<Fast Power> | ||
-------------- | ||
Fast Power is an optimized algorithm to compute exponentiation in a short time. | ||
|
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.
It would be helpful for others if you could also mention in 1 or 2 lines more what the algorithm does.
Regarding adding tests. Shall I add some sample tests commented?
|
Like the example you gave. |
I have updated the file with the required changes alongside adding sample tests.
NumberTheory/FastPower.cpp
Outdated
//Sample Tests | ||
TEST_CASE("Base cases", "[fast_power]") { | ||
REQUIRE(fast_power(2,2) == 4); | ||
REQUIRE(fast_power(2,4) == 16); |
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.
I think you didn't exactly understand how to add tests, but no worries 😄! Read the second comment in issue #41 to know the exact steps in detail.
Removed test cases from the source file.
I have now added a test file for fastPower.cpp, and edited fastPower.cpp to be compatible. |
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.
Well done on adding the tests! 👍
However there are a few issues I have mentioned in the review. Also, the f
in the name of the test file should be capital.
Test/NumberTheory/fastPower.test.cpp
Outdated
|
||
TEST_CASE("Overflow cases", "[fast_power]") { | ||
REQUIRE(fast_power(2,100) == 0); | ||
REQUIRE(fast_power(10,99) == 0); |
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.
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.
I think you meant fast_power(2 ,100)
in the first one.
Anyway, regarding large numbers, to fix the output being 0
we can output them modulo a large number such as 1000000000007
, but not a huge number like 2^64
. Where fast_power(2, 100)
will be 40955801449
.
Regarding the last statement, do you mean changing ull
to Ull
?
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.
Yes, I meant fast_power(2, 100)
in the first one. Fixed it.
I don't think you need to output modulo a specific number. The result will automatically be modulo MAX_ULL
, which is 264-1.
No, ull
is fine. I meant you need to add the suffix U
to unsigned numbers greater than 263-1 to prevent warnings.
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.
Aha! Sorry for the misunderstanding.
NumberTheory/FastPower.cpp
Outdated
int main() | ||
{ | ||
//Testing the function | ||
int base,exponent; |
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.
int
ull
Test/NumberTheory/fastPower.test.cpp
Outdated
|
||
TEST_CASE("Base cases", "[fast_power]") { | ||
REQUIRE(fast_power(2,2) == 4); | ||
REQUIRE(fast_power(2,4) == 16); |
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.
Under "Base cases", check the values of the following:
fast_power(0, 0)
isundefined
orNaN
. Comment this case here and handle it properly in the code.fast_power(0, 1)
should be0
fast_power(1, 0)
should be1
fast_power(1, 1)
should be1
Test/NumberTheory/FastPower.test.cpp
Outdated
REQUIRE(fast_power(1,1) == 1); | ||
REQUIRE(fast_power(2,2) == 4); | ||
REQUIRE(fast_power(2,2) == 4); | ||
REQUIRE(fast_power(2,4) == 16); |
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 last 2 can be added under "Normal cases". Also the (2, 2) case has a duplicate.
Requested changes are all done. Are there any other issues to be fixed? |
Test/NumberTheory/FastPower.test.cpp
Outdated
|
||
TEST_CASE("Overflow cases", "[fast_power]") { | ||
REQUIRE(fast_power(2,100) == 68719476736); | ||
REQUIRE(fast_power(10,99) == 4440381706574496940U); |
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.
Both these tests are failing, and I think the reason is that at some step of the calculation, the multiplication produces the value 264, which for a 64-bit unsigned integer (unsigned long long
) is 0, and so the final value also becomes 0 (as anything multiplied by 0 is 0).
This could be solved by taking the modulus of the values at each step, like you suggested previously, but the value of that (prime) number should be as close as possible to 264-1, to get exact results for a larger range of values.
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.
I have tried returning the result modulo several prime numbers. The number 1000000000007
seems to be suitable, as a number bigger than it will result in fast_power(2,100)
being greater than 2^100 mod (2^64-1)
.
fast_power(2,100)
now returns 40955801449
.
However, cases like fast_power(33,33)
still cause overflow.
What do you think?
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.
I thought about this for a while and I think what we need to do is check how many digits the result is going to take. That would be done as follows:
digits_required = floor(exponent * log10(base)) + 1
If digits_required > 19
, then use modulo 1000000000007
and tell the user about this too. Otherwise, we can directly use the result.
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.
Great idea!
but I want to note that we apply modulus 1000000000007
every time we return a value in fast_power()
to prevent overflow in the function.
So we may create two functions, one that uses %1000000000007
and one that doesn't. But to prevent this, I added a third parameter to the function called "mod" where we apply %1000000000007
if digits_required > 19
or else apply %10^18
which is a number that won't affect the output result.
This is how the code is right now:
if (digits_required > 19)
{
cout<<endl<<fast_power(base,exponent,1000000000007)<<endl;
cout<<"*The output is modulo 10^12+7"<<endl;
}
else
{
cout<<endl<<fast_power(base,exponent,1000000000000000000)<<endl;
}
Shall I commit with the final changes so we can close the PR and put "FastPower" behind our backs? if that's not the most convenient thing to do right now I have no problem.
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.
Yes, passing a third parameter is the right way instead of having 2 similar functions. But use ULLONG_MAX
as the mod value in the else
case instead of 1018.
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.
1012+7 is not prime! So the modulo may be 0 in some cases. Use 109+7 instead.
There have been lots of suggestions recently by interested contributors to add more algorithms and data structures to the project, which I have currently put on hold because I want to close issue #74 first, as it would require a complete reorganisation of files and some refactoring of code. I previously thought that I would work on #74 once the currently active PRs are merged, but I feel that it would take much longer that way. So, if it's not too inconvenient for you, I would like to work on issue #74 as soon as possible. The remaining work on this PR (and others) can be carried on afterwards. Once the project is refactored, all you would need to do is So, what do you say? |
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.
One last change and then we're good to merge!
NumberTheory/FastPower.cpp
Outdated
|
||
using namespace std; | ||
typedef unsigned long long ull; | ||
|
||
//Function that returns base raised to the exponent | ||
ull fast_power (ull base,ull exponent) | ||
ull fast_power (ull base,ull exponent,ull mod) |
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.
Give mod
the default value ULLONG_MAX
so that it doesn't need to be passed to the function if modulus of the result is not required.
Test/NumberTheory/FastPower.test.cpp
Outdated
//REQUIRE(fast_power(0,0) == undefined); | ||
REQUIRE(fast_power(0,1,ULLONG_MAX) == 0); | ||
REQUIRE(fast_power(1,0,ULLONG_MAX) == 1); | ||
REQUIRE(fast_power(1,1,ULLONG_MAX) == 1); |
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.
ULLONG_MAX
should be removed from the tests too. You missed this.
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.
Sure! Sorry for this.
Congratulations on your first PR merge! 🎉 And thanks for contributing to the project 😃 |
Thank you! 😃 Was great working with you 😄 |
This is my first PR, please tell me if there are any issues to be fixed.
Relates to issue #75.