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
feat: Add ncr mod p code #1325
feat: Add ncr mod p code #1325
Changes from 1 commit
bd98630
e44b730
f6df24a
51a1fe6
2ba05ed
e09a057
8e9803d
8111f88
ba954d4
2ad2f72
f8c9934
350508f
4741898
5b69ba5
8b747e2
a8401d4
7f33ea8
db28362
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,96 @@ | ||||||||||||||||
/** | ||||||||||||||||
* @file | ||||||||||||||||
* @brief This program aims at calculating nCr modulo p | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Provide a Wikipedia link in Markdown format (if available/possible). |
||||||||||||||||
* | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
*/ | ||||||||||||||||
|
||||||||||||||||
#include <cassert> | ||||||||||||||||
#include <iostream> | ||||||||||||||||
#include <vector> | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
|
||||||||||||||||
/** Finds the value of x, y such that a*x + b*y = gcd(a,b) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
* | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
* @params[in] the numbers 'a', 'b' and address of 'x' and 'y' from above | ||||||||||||||||
* equation | ||||||||||||||||
* @returns the gcd of a and b | ||||||||||||||||
*/ | ||||||||||||||||
int64_t gcdExtended(int64_t a, int64_t b, int64_t *x, int64_t *y) { | ||||||||||||||||
if (a == 0) { | ||||||||||||||||
*x = 0, *y = 1; | ||||||||||||||||
return b; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
int64_t x1 = 0, y1 = 0; | ||||||||||||||||
int64_t gcd = gcdExtended(b % a, a, &x1, &y1); | ||||||||||||||||
|
||||||||||||||||
*x = y1 - (b / a) * x1; | ||||||||||||||||
*y = x1; | ||||||||||||||||
return gcd; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/** Find modular inverse of a with m i.e. a number x such that (a*x)%m = 1 | ||||||||||||||||
* | ||||||||||||||||
* @params[in] the numbers 'a' and 'm' from above equation | ||||||||||||||||
* @returns the modular inverse of a | ||||||||||||||||
*/ | ||||||||||||||||
int64_t modInverse(int64_t a, int64_t m) { | ||||||||||||||||
int64_t x = 0, y = 0; | ||||||||||||||||
int64_t g = gcdExtended(a, m, &x, &y); | ||||||||||||||||
if (g != 1) { // modular inverse doesn't exist | ||||||||||||||||
return -1; | ||||||||||||||||
} | ||||||||||||||||
else { | ||||||||||||||||
int64_t res = (x % m + m) % m; | ||||||||||||||||
return res; | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
std::vector<int64_t> fac; | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using global variables, they may cause overflows and other issues. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what if I keep that variable inside namespace? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Easiest thing you can do is to pass them as local function parameters. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I refactored the code so that the factorial vector and the remaining functions are inside a class |
||||||||||||||||
|
||||||||||||||||
/** Find nCr % p | ||||||||||||||||
* | ||||||||||||||||
* @params[in] the numbers 'n', 'r' and 'p' | ||||||||||||||||
* @returns the value nCr % p | ||||||||||||||||
*/ | ||||||||||||||||
int64_t ncr(int64_t n, int64_t r, int64_t p) { | ||||||||||||||||
// Base cases | ||||||||||||||||
if (r > n) { | ||||||||||||||||
return 0; | ||||||||||||||||
} | ||||||||||||||||
if (r == 1) { | ||||||||||||||||
return n % p; | ||||||||||||||||
} | ||||||||||||||||
if (r == 0 || r == n){ | ||||||||||||||||
return 1; | ||||||||||||||||
} | ||||||||||||||||
// fac is a global array with fac[r] = (r! % p) | ||||||||||||||||
int64_t denominator = modInverse(fac[r], p); | ||||||||||||||||
if (denominator < 0) { // modular inverse doesn't exist | ||||||||||||||||
return -1; | ||||||||||||||||
} | ||||||||||||||||
denominator = (denominator * modInverse(fac[n - r], p)) % p; | ||||||||||||||||
if (denominator < 0) { // modular inverse doesn't exist | ||||||||||||||||
return -1; | ||||||||||||||||
} | ||||||||||||||||
return (fac[n] * denominator) % p; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
int main() { | ||||||||||||||||
KaustubhDamania marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
// populate the fac array | ||||||||||||||||
const int64_t size = 1e6 + 1; | ||||||||||||||||
fac = std::vector<int64_t>(size); | ||||||||||||||||
fac[0] = 1; | ||||||||||||||||
const int64_t p = 1e9 + 7; | ||||||||||||||||
for (int i = 1; i <= size; i++) { | ||||||||||||||||
fac[i] = (fac[i - 1] * i) % p; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// test 6Ci for i=0 to 7 | ||||||||||||||||
for (int i = 0; i <= 7; i++) { | ||||||||||||||||
std::cout << 6 << "C" << i << " = " << ncr(6, i, p) << "\n"; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// (52323 C 26161) % (1e9 + 7) = 224944353 | ||||||||||||||||
assert(ncr(52323, 26161, p) == 224944353); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add the assert checks in a separate test function. 🙂 |
||||||||||||||||
std::cout << "Assertion passed, (52323 C 26161) % (1e9 + 7) = 224944353\n"; | ||||||||||||||||
} |
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 add a detailed description using
@details
.