Skip to content
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

fix:Fit Binominal calculate.cpp to guidelines #2464

Closed
wants to merge 12 commits into from
102 changes: 58 additions & 44 deletions math/binomial_calculate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,90 +3,104 @@
* @brief Program to calculate [Binomial
* coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient)
*
* @details
* quoted from: [Weisstein, Eric W. "Binomial Coefficient." From MathWorld--A
* Wolfram Web
* Resource.](https://mathworld.wolfram.com/BinomialCoefficient.html) "The
* binomial coefficient [; meaning n above k in brackets, how binomial
* coefficients are notated] (n; k) is the number of ways of picking k unordered
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
* outcomes from n possibilities, also known as a combination or combinatorial
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
* number. The symbols [ _ representing subscript ] _nC_k and (n; k) are used to
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
* denote a binomial coefficient, and are sometimes read as "n choose k." (n; k)
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
* therefore gives the number of k-subsets possible out of a set of n distinct
* items. For example, The 2-subsets of {1,2,3,4} are the six pairs {1,2},
* {1,3}, {1,4}, {2,3}, {2,4}, and {3,4}, so (4; 2)=6." [Another good
realstealthninja marked this conversation as resolved.
Show resolved Hide resolved
* example/explanation](https://math.stackexchange.com/questions/2172355/probability-notation-two-numbers-stacked-inside-brackets)
*
* @note An identity of the binomial coefficient is (n; n-k) This is explained
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
* partially in the comments of this implementation but in more detail at [Prof.
* Tesler: Chapter 3.3, 4.1, 4.3. Binomial Coefficient
* Identities](https://mathweb.ucsd.edu/~gptesler/184a/slides/184a_ch4slides_17-handout.pdf
* page 2)
*
* @author [astronmax](https://github.com/astronmax)
*/

#include <cassert> /// for assert
#include <cstdint> /// for int32_t type
#include <cstdlib> /// for atoi
#include <iostream> /// for IO operations

/**
* @namespace math
* @brief Mathematical algorithms
*/
namespace math {
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
/**
* @namespace binomial
* @brief Functions for [Binomial
* coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient)
* implementation
*/
namespace binomial {
realstealthninja marked this conversation as resolved.
Show resolved Hide resolved
/**
* @brief Function to calculate binomial coefficients
* @param n first value
* @param k second value
* @return binomial coefficient for n and k
* @param n number of possibilities
* @param k size of subset
* @return n if k == 1
* @return 1 if k == 0
* @return result if k != 0 || 1
*/
size_t calculate(int32_t n, int32_t k) {
// basic cases
if (k > (n / 2))
k = n - k;
if (k == 1)
return n;
if (k == 0)
/*!
* Why do we do if k > (n/2) then k = n-k? Because (n;k) is the same as
* (n;n-k) or, in this case, (6;4) is the same as (6;2) since both are
* calculated for n!/k!(n-k)! , in this case 6!/4!2! . By replacing k with
* n-k we get 6!/2!4! which is the same sum. the benefit however, is our
* loop further on in this implementation now requires less iterations to
* find the same answer.
*
* k == 1 and k == 0 follow the same rule as n^1 and n^0 respectively
*/
if (k == 0) {
return 1;
} else if (k == 1) {
return n;
} else if (k > (n / 2)) {
k = n - k;
}

/*!
* (n - k) + i returns 1 higher each loop imitating a factorial calculation.
* Then imagine i as the size of each set, divide by it to find the amount
* of possible sets in result amount of possibilities
*/
size_t result = 1;
for (int32_t i = 1; i <= k; ++i) {
result *= n - k + i;
result *= (n - k) + i;
result /= i;
}

return result;
}
} // namespace binomial
} // namespace math

/**
* @brief Test implementations
* @returns void
*/
static void tests() {
// tests for calculate function
assert(math::binomial::calculate(1, 1) == 1);
assert(math::binomial::calculate(57, 57) == 1);
assert(math::binomial::calculate(6, 3) == 20);
assert(math::binomial::calculate(10, 5) == 252);
assert(math::binomial::calculate(20, 10) == 184756);
assert(math::binomial::calculate(30, 15) == 155117520);
assert(math::binomial::calculate(40, 20) == 137846528820);
assert(math::binomial::calculate(50, 25) == 126410606437752);
assert(math::binomial::calculate(60, 30) == 118264581564861424);
assert(math::binomial::calculate(62, 31) == 465428353255261088);
assert(math::calculate(1, 1) == 1);
assert(math::calculate(57, 57) == 1);
assert(math::calculate(6, 3) == 20);
assert(math::calculate(10, 5) == 252);
assert(math::calculate(20, 10) == 184756);
assert(math::calculate(30, 15) == 155117520);
assert(math::calculate(40, 20) == 137846528820);
assert(math::calculate(50, 25) == 126410606437752);
assert(math::calculate(60, 30) == 118264581564861424);
assert(math::calculate(62, 31) == 465428353255261088);

std::cout << "[+] Binomial coefficients calculate test completed"
<< std::endl;
}

/**
* @brief Main function
* @param argc commandline argument count
* @param argv commandline array of arguments
* @returns 0 on exit
*/
int main(int argc, const char* argv[]) {
int main() {
tests(); // run self-test implementations

if (argc < 3) {
std::cout << "Usage ./binomial_calculate {n} {k}" << std::endl;
return 0;
}

int32_t n = atoi(argv[1]);
int32_t k = atoi(argv[2]);

std::cout << math::binomial::calculate(n, k) << std::endl;
return 0;
}